commit 34d8b4106b0f65a127437e432ccfbf53cae94f81 Author: Joerg Deckert Date: Mon Jun 23 15:12:41 2014 +0200 initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f128240 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Auto detect text files and perform LF normalization + +* text=auto + +*.bat text eol=crlf diff --git a/GUI-Demo.md b/GUI-Demo.md new file mode 100644 index 0000000..f2bd687 --- /dev/null +++ b/GUI-Demo.md @@ -0,0 +1,106 @@ +GUI-DEMO +======== + +Text based UI Elements for Propeller for use with the VGA_HiRes_Text Driver + + +Demo / Text program +------------------- + + GUIDemo.spin - the demo app + + +Files that comprise the UI Elements +----------------------------------- + + FILE LONGS USED DESCRIPTION + PROG DATA + ---------------------- ------ ------ ----------------------------------- + GUIBase.spin 2,472 1,643 - UI control and infrastructure + InputField.spin 168 6 - Input Field object + MenuItem.spin 62 13 - Menu Item object + PushButton.spin 124 12 - Push Button object + RadioCheck.spin 78 13 - Radio Button and Check Box object + SimpleBox.spin 62 0 - Basic Box object + SpinBox.spin 191 12 - Spin Button object + TextBox.spin 206 4 - Text Box object + StatusLamp.spin 52 6 - Status Annunciator + +Required Drivers +---------------- + Vga_HiRes_Text.spin - VGA High Resolution Text Driver + Mouse.spin - PS2 Mouse driver + Keyboard.spin - PS2 Keyboard Driver + + +Description +----------- + +This text based UI for the High Res VGA Driver will work in all resolutions that +the driver supports, the demo itself is setup for 800x600 but will show OK at +1024x768 too. At 640x480 it will not look right (needs to be repositioned and +re-sized), It is very much a fist principles implementation with no bells and +whistles. It supports a static UI and only the basic functionality. To use the +UI Elements the user must decide on a screen layout and then place the elements +there. You only need to include the objects that you plan to use, you do not +have to declare them all. This is done at the top of GUIBase.spin in the +constants where you delcare how mane of each element type you will need. + + +There are 6 simple steps to using these objects: + + 1. Configure the numbers and types of GUI elements you need in the GUI Element + Inventory section of the CON section of the GUIBase.spin file. See the top + of that file for simple directions. + + 2. Declare the GUI object in your application's OBJ section. + + OBJ + GUI : "GUIBase" + + 3. Initialize the GUI object in your application's startup. You will need to + pass in the VGA, Mouse and Keyboard pin assignments you are using for each + of thise devices. This will initialise the GUI data structures and start the + VGA (High Res Text), Mouse, and Keyboard drivers. + + GUI.Init( VGABase, MouseDat, MouseCLk, KeyboardDat, KeyboardClk ) + + 4. Create the GUI Elements as required by your application by calling the + specific "Init" fucntion in GUIBase.spin. Note that all GUI interation and + control will be via the functions in GUIBase.spin, you will not need to + access the individual GUI Element files directly. For each element you + create you will need to have a variable in your VAR section to hold its + identifier. For example + + PUSH1 := GUI.PUSHInit( ... ) + + Creates a new pushbutton object identified by the variable PUSH1 which was + declared as a byte in the VAR section. This variable will be used to pass + in to calls to handle the object and will be returned to you for action in + the event that the mouse is clicked on it. + + 5. Create a main loop for your application that will service both your + application and run the processing for the UI. The UI is processed via the + ProcessUI function in GUIBase.spin. + + repeat + ProcessApplication + elem := GUI.ProcessUI + if elem <> -1 + case elem + PUSH1: CallYourFunctionForPUSH1() + PUSH2: CallYourFunctionForPUSH1() + etc... + + The ProcessUI function will handle the UI for you, highlighting elements as + the mouse passes over them, processing mouse clicks and keyboard entry, etc. + It will return -1 if no action is required (i.e. you did not click on + anything). If the user clicked on something (i.e. Push Button PUSH1 perhaps) + it will return the guid of the element that requires action (i.e. PUSH1). + In this case you will need to perform an action associated with the Push + Button. It is probably best to keep the main loop clean and call a function + to perform tha action rather than do it right in the loop. That makes it + easier to read and maintain. + + 6. Create your user action functions, one for each GUI Element that will do + something. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8b1b70f --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +Toolbox 3 +========= + +Neues Futter für den Hive. Wie bei der ersten Toolbox genügt es den Inhalt des +Ordners "BIN/SDCARD" auf ein passendes Medium zu kopieren. + + +Inhalt: Ordner tbox-3 +===================== + +BOING +----- + +Eine Icone der Retrokultur auf dem Hive als Musikplayer! +Basis ist der geniale Grafikcode von kuroneko. + + - alle Dateien müssen sich in einem Verzeichis befinden + - weitere dmp-Dateien werden wie in einem Player abgespielt + +Tastencodes: + + [n] - nächster Titel + [p] - Pause + [esc] - Programmende + +Graphics-Code: kuroneko +SIDcog: Ahle2 +Hive-Code: drohne235 + + +GUI-DEMO +-------- + +Demo von einem textbasierten GUI-Code + + +PLEXBUS +------- + +Programmierbeispiele für den PlexBus und die Sepia-Karte + + +TRIBORG +------- + +Soundplayer diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..63bb99d --- /dev/null +++ b/make.bat @@ -0,0 +1,58 @@ +echo on +date /T +time /T + +REM # Definitionen +REM set D="-D __DEBUG -D __LANG_EN" +REM set D="-D __LANG_EN" +set D="-D __LANG_DE" + +REM # Pfade +set bin="..\Bin" +REM set bin="\home\ftp\hive" +set sdtbox="%bin%\sdcard\tbox-3" +set libpath="..\TriOS\lib" +set BSTC=bstc.exe + +REM ---------------------------------------------------------------- +REM Alte Versionen löschen + +rmdir %sdtbox% /S /Q +mkdir %sdtbox% +mkdir %sdtbox%\boing +mkdir %sdtbox%\gui-demo +mkdir %sdtbox%\plexbus +mkdir %sdtbox%\triborg + +REM del %sdsys%\xxxxxx +REM mkdir %sdsys% + +REM ---------------------------------------------------------------- +REM Bin-Dateien erzeugen, kopieren + +%BSTC% -L %libpath% %D% -b -O a .\source\boing\boing-reg.spin +move boing-reg.binary "%sdtbox%\boing\boing.bin" +%BSTC% -L %libpath% %D% -b -O a .\source\boing\boing-bel.spin +move boing-bel.binary "%sdtbox%\boing\boing.bel" +%BSTC% -L %libpath% %D% -D __ADM_FAT -D __ADM_SID -b -O a ..\TriOS\flash\administra\admflash.spin +move admflash.binary "%sdtbox%\boing\boing.adm" +copy .\source\sid\boing.sid "%sdtbox%\boing\" +copy .\source\sid\*.dmp "%sdtbox%\boing\" + +%BSTC% -L %libpath% %D% -b -O a .\source\triborg\triborg-reg.spin +move triborg-reg.binary "%sdtbox%\triborg\triborg.bin" +%BSTC% -L %libpath% %D% -b -O a .\source\triborg\triborg-bel.spin +move triborg-bel.binary "%sdtbox%\triborg\triborg.bel" +%BSTC% -L %libpath% %D% -D __ADM_FAT -D __ADM_SID -b -O a ..\TriOS\flash\administra\admflash.spin +move admflash.binary "%sdtbox%\triborg\triborg.adm" +copy .\source\sid\triborg.sid "%sdtbox%\triborg\" +copy .\source\sid\*.dmp "%sdtbox%\triborg\" + +for %%x in (.\source\plexbus\*.spin) do %BSTC% -L %libpath% %D% -b -O a %%x +rename *.binary *.bin +move *.bin "%sdtbox%\plexbus\" + +%BSTC% -L %libpath% %D% -e -O a .\source\gui-demo\guidemo.spin +move guidemo.eeprom "%sdtbox%\gui-demo\guidemo.bel" + +echo off diff --git a/make.sh b/make.sh new file mode 100755 index 0000000..26d5f74 --- /dev/null +++ b/make.sh @@ -0,0 +1,58 @@ +#! /bin/sh + +# Definitionen +##D="-D __DEBUG -D __LANG_EN" +##D="-D __LANG_EN" +D="-D __LANG_DE" + +# Pfade +bin="../Bin" +##bin="/home/ftp/hive" +sdtbox="${bin}/sdcard/tbox-3" +libpath="../TriOS/lib" +BSTC="bstc" + +# ---------------------------------------------------------------- +# Alte Versionen löschen + +rm -rf ${sdtbox} +mkdir -p ${sdtbox} +mkdir ${sdtbox}/boing +mkdir ${sdtbox}/gui-demo +mkdir ${sdtbox}/plexbus +mkdir ${sdtbox}/triborg + +##rm -f ${sdsys}/xxxxxx +##mkdir -p ${sdsys} + + +# ---------------------------------------------------------------- +# Bin-Dateien erzeugen, kopieren + + +${BSTC} -L ${libpath} ${D} -b -O a source/boing/boing-reg.spin +mv boing-reg.binary "${sdtbox}/boing/boing.bin" +${BSTC} -L ${libpath} ${D} -b -O a source/boing/boing-bel.spin +mv boing-bel.binary "${sdtbox}/boing/boing.bel" +${BSTC} -L ${libpath} ${D} -D __ADM_FAT -D __ADM_SID -b -O a ../TriOS/flash/administra/admflash.spin +mv admflash.binary "${sdtbox}/boing/boing.adm" +cp source/sid/boing.sid "${sdtbox}/boing/" +cp source/sid/*.dmp "${sdtbox}/boing/" + +${BSTC} -L ${libpath} ${D} -b -O a source/triborg/triborg-reg.spin +mv triborg-reg.binary "${sdtbox}/triborg/triborg.bin" +${BSTC} -L ${libpath} ${D} -b -O a source/triborg/triborg-bel.spin +mv triborg-bel.binary "${sdtbox}/triborg/triborg.bel" +${BSTC} -L ${libpath} ${D} -D __ADM_FAT -D __ADM_SID -b -O a ../TriOS/flash/administra/admflash.spin +mv admflash.binary "${sdtbox}/triborg/triborg.adm" +cp source/sid/triborg.sid "${sdtbox}/triborg/" +cp source/sid/*.dmp "${sdtbox}/triborg/" + +for FILE in source/plexbus/*.spin ; do + ${BSTC} -L ${libpath} ${D} -b -O a ${FILE} + BASE="`basename ${FILE} .spin`" + mv "${BASE}.binary" "${sdtbox}/plexbus/${BASE}.bin" +done + +${BSTC} -L ${libpath} ${D} -e -O a source/gui-demo/guidemo.spin +mv guidemo.eeprom "${sdtbox}/gui-demo/guidemo.bel" diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..482f6e8 --- /dev/null +++ b/release.sh @@ -0,0 +1,37 @@ +#! /bin/sh + +# Definitionen +VERSION="1.1" + +# Pfade +ARCHIV="HIVE-Toolbox3-${VERSION}" +MAKE="./make.sh" +BIN="Bin" + +# ---------------------------------------------------------------- +# Alte Versionen löschen + +rm -rf ../${BIN} +rm -f ../${ARCHIV}-bin.zip +rm -f ../${ARCHIV}-src.zip + +# ---------------------------------------------------------------- +# Binaries erstellen + +${MAKE} + +# ---------------------------------------------------------------- +# Archive erstellen + +mkdir .tmp +for file in *.md ; do cp "$file" .tmp/"${file/.md}".txt ; done +cd .tmp +zip -r9 ../../${ARCHIV}-bin.zip * +zip -r9 ../../${ARCHIV}-src.zip * +cd .. +rm -rf .tmp + +zip -r9 ../${ARCHIV}-src.zip sounds source make* + +cd .. +zip -r9 ${ARCHIV}-bin.zip ${BIN} diff --git a/source/boing/boing-bel-background.spin b/source/boing/boing-bel-background.spin new file mode 100644 index 0000000..69cee18 --- /dev/null +++ b/source/boing/boing-bel-background.spin @@ -0,0 +1,224 @@ +'' +'' VGA scanline driver 400x300 - background renderer +'' +'' Based on "Ball" demo for Gameduino +'' Copyright (c) 2011 by James Bowman +'' +'' Author: Marko Lukat +'' Last modified: 2012/12/24 +'' Version: 0.9 +'' +OBJ + system: "boing-bel-corecon" + +PUB null +'' This is not a top level object. + +PUB init(ID, mailbox) + + return system.launch(ID, @entry, mailbox) + +DAT org 0 ' background renderer + +entry jmpret $, #setup ' once + + rdlong indx, blnk ' | + cmpsub indx, scry wz ' | + if_ne jmp #$-2 ' waiting for last line to be fetched + +' Skip 26 sync lines and advance by a further 161 hub windows. This pushes the +' first background renderer wrlong beyond the first video renderer line rdlong +' if it were to render scanline -1. +' After the waitcnt we have another 9 insn (36 + 18 + 10 = 64, 4 hub windows). + + mov cnt, cnt + add cnt, $+1 + long 13{18} + 10 + 132*16*26 + 16*(161 - 4) + +loop waitcnt cnt, one ' initial sync point + + call #fill ' fill background + + add indx, #1 ' line done, advance + cmpsub indx, scry wz ' optionally wrap line index + if_z add cnt, two + + +one long 132*16*2 ' skip two scan lines +two long 132*16*28 ' skip all sync lines + + jmp #loop + +' support code + +fill + mov addr, indx + shr addr, #1 wc + add read, addr +fill_ret long 0-0 ' pipeline +read mov addr, $+3 + if_c shr addr, #16 + jmpret read, addr ' render background + + word eins[5], zwei[3] + word drei[21], zwei[3], drei[21], zwei[3], drei[21], zwei[3], drei[21], zwei[3] + word drei[21], zwei[3], drei[21], zwei[3], drei[21], zwei[3], drei[21], zwei[3] + word drei[21], zwei[3], drei[21], zwei[3], drei[21], zwei[3], drei[21], zwei[3] + word eins[4] + +eins mov addr, base ' 100(A) + + mov gindx, gindx0 + mov gflag, #0 + + mov qcnt, #100 +:loop wrlong ty_A, addr + add addr, #4 + djnz qcnt, #:loop + + jmp fill_ret + +zwei mov addr, base ' AB(48(CC))DA + + cmp gflag, #0 wz + if_z mov gflag, #1 + if_z rdword gline0, gindx + if_z add gindx, #4 + + wrlong ty_A, addr + add addr, #4 + wrlong ty_B, addr + add addr, #4 + + mov qcnt, #96/2 +:loop wrlong ty_C, addr + add addr, #4 + cmp qcnt, #1 wz ' last run? + wrlong ty_C, addr + add addr, #4 + if_ne djnz qcnt, #:loop + + wrlong ty_D, addr + add addr, #4 + wrlong ty_A, addr + + jmp fill_ret + +drei mov addr, base ' AB(16(DAAAAB))DA + + mov gline, gline0 + mov gflag, #0 + + wrlong ty_A, addr + add addr, #4 + wrlong ty_B, addr + add addr, #4 + + mov qcnt, #16 + +:loop mov ty_x1, ty_D ' leere punkte + mov ty_X2, ty_A + mov ty_X3, ty_B + shr gline,#1 wc + if_nc jmp #:empty + mov ty_X1, ty_C ' gefüllte punkte + mov ty_X2, ty_C + mov ty_X3, ty_C +:empty + wrlong ty_X1, addr + add addr, #4 + cmp qcnt, #1 wz ' last run? + '--------------------- + wrlong ty_X2, addr + add addr, #4 + wrlong ty_X2, addr + add addr, #4 + wrlong ty_X2, addr + add addr, #4 + wrlong ty_X2, addr + add addr, #4 + '--------------------- +:end wrlong ty_X3, addr + add addr, #4 + if_ne djnz qcnt, #:loop + + wrlong ty_D, addr + add addr, #4 + wrlong ty_A, addr + + jmp fill_ret + + + +' initialised data and/or presets + +blnk long -4 +base long NEGX + +ty_A {----} long $01010101 * C0 +ty_B {---#} long $00010101 * C0 + $01000000 * C1 +ty_C {####} long $01010101 * C1 +ty_D {##--} long $01010000 * C0 + $00000101 * C1 +ty_X1 long 0 +ty_X2 long 0 +ty_X3 long 0 + +gindx0 long 400 +gindx long 0 +gline0 long 0 +gline long 0 +gflag long 0 + +' Stuff below is re-purposed for temporary storage. + +setup add base, par ' scanline buffer (%%) + add blnk, base wc ' frame indicator + + rdword indx, blnk wz ' (%%) + if_nz mov scry, indx wc ' (%%) + if_c_or_nz jmp #$-2 ' auto-detect res_y + +' The loop is only left once a non-zero value has been written to scry +' and indx transitions to zero afterwards. + + add gindx0, par + jmp %%0 ' return + + fit + +' uninitialised data and/or temporaries + +scry res 1 ' must be 1st/2nd (%%) +indx res 1 ' | + +addr res 1 +qcnt res 1 + +tail fit + +CON + C0 = %%2220 ' background + C1 = %%1110 ' grid + +DAT +{{ + + TERMS OF USE: MIT License + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + associated documentation files (the "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +}} +DAT diff --git a/source/boing/boing-bel-corecon.spin b/source/boing/boing-bel-corecon.spin new file mode 100644 index 0000000..125188b --- /dev/null +++ b/source/boing/boing-bel-corecon.spin @@ -0,0 +1,42 @@ +'' +'' prerequisites, dependencies & Co +'' +'' Author: Marko Lukat +'' Last modified: 2011/10/22 +'' Version: 0.9 +'' +CON + _clkmode = XTAL1|PLL16X + _xinfreq = 5_000_000 + +CON + ID_0 = $30B3309C + ID_1 = $9ED2732B + ID_2 = $38343032 ' cog binary magic number (2048) + + OVERLAY = %00000000_00000001 ' cog binary is an overlay + MAPPING = %00000000_00000010 ' translation table is present + +PUB null +'' This is not a top level object. + +PUB launch(ID, code, data) +'' PASM quick launch using a specific or the next available ID. +'' +'' parameters +'' ID: cog ID +'' 0..7: coginit, otherwise cognew (may fail) +'' code: address of code fragment (4n) +'' data: cognew/coginit parameter (4n) +'' +'' result +'' == 0: [ABORT] thread creation failed (cognew only) +'' <> 0: thread/cog ID + 1 + + ifnot (ID >> 3) + coginit(ID++, code, data) + elseifnot ID := cognew(code, data) + 1 + abort + return ID + +DAT diff --git a/source/boing/boing-bel-driver.spin b/source/boing/boing-bel-driver.spin new file mode 100644 index 0000000..622fb5a --- /dev/null +++ b/source/boing/boing-bel-driver.spin @@ -0,0 +1,553 @@ +'' +'' VGA scanline driver 400x300 (single cog) - video driver and pixel generator +'' +'' Author: Marko Lukat +'' Last modified: 2013/01/11 +'' Version: 0.10 +'' +'' - timing signalled as SVGA 800x600 +'' - vertical blank start sets frame indicator (FI) to 0 +'' - once the Nth scanline has been fetched the FI is set to N+1 +'' +'' 20121007: added minimal translation table +'' 20121229: now capable of using 64/256 colours (RRGGBBHV / RRGGBBgr + xxxxxxHV) +'' - 64c: $FC/2/2 (vpin/vgrp/sgrp) +'' - 256c: $FF/2/3 +'' 20121230: simplified vertical blanking code +'' +'' Note: With idle state being %00 {%hv} the switch code can be further simplified. +'' As this was the first converted driver I left the generic solution intact +'' so it can easily be adapted for other drivers (with non-zero idle state). +'' +OBJ + system: "boing-bel-corecon" + +PUB null +'' This is not a top level object. + +PUB init(ID, mailbox) + + return system.launch(ID, @driver, mailbox) + +DAT org 0 ' cog binary header + +header_2048 long system#ID_2 ' magic number for a cog binary + word header_size ' header size + word system#MAPPING ' flags + word 0, 0 ' start register, register count + + word @__table - @header_2048 ' translation table byte offset + +header_size fit 16 + +DAT org 0 ' video driver + +driver jmpret $, #setup ' -4 once + + mov dira, mask ' drive outputs + +' horizontal timing 400(800) 20(40) 64(128) 44(88) +' vertical timing 300(600) 1(1) 4(4) 23(23) + +vsync mov lcnt, #0 ' | + wrlong lcnt, blnk ' reset line counter (once) + + mov vscl, full ' 32/528 + +' mov ecnt, #1 + waitvid sync, #%%0011 ' front porch +' djnz ecnt, #$-1 + + xor sync, #$0101 ' active + + mov ecnt, #4 + waitvid sync, #%%0011 ' vertical sync + djnz ecnt, #$-1 + + xor sync, #$0101 ' inactive + + mov ecnt, #23 + waitvid sync, #%%0011 ' back porch + djnz ecnt, #$-1 + +' Vertical sync chain done, do visible area. + + mov scnt, #res_y + +:loop call #prefix ' sync and back porch + jmpret suffix_ret, #emit_0 ' visible line and front porch + + call #prefix ' sync and back porch + jmpret suffix_ret, #emit_1 ' visible line and front porch + + djnz scnt, #:loop ' repeat for all lines + + jmp #vsync ' next frame + + +prefix mov vscl, slow ' 32/108 + waitvid sync, #%%2011 ' latch sync and back porch + + mov cnt, cnt ' cover sync pulse period (%%) + add cnt, #9{14}+(64 * 4) ' because we drive sync lines + waitcnt cnt, #135 ' manually next (%%) + + mov outa, idle ' take over sync lines (##) +prefix_ret ret + + +suffix mov vscl, hs_f ' 1/20 + waitvid sync, #%%02 ' latch front porch + +' waitvid +' | S D e . . . R | mov vcfg | mov outa | +' clock  +' │ │ │ │ +' PLL  +' pixel 1:4 │+4 +' │ │ pixel %%2 │ pixel %%0 | +' outa  + + mov vcfg, vcfg_sync ' drive/change sync lines (##) + mov outa, #0 ' stop interfering + + if_nc wrlong lcnt, blnk ' report current line +suffix_ret ret + +' Even line emitter (fetch & emit). + +emit_0 waitcnt cnt, #0 ' re-sync after back porch (%%) + +' At this point the video h/w is driving the sync lines low (colour %%2). +' outa has taken over long ago so we can switch configuration here. + + mov vcfg, vcfg_norm ' -12 disconnect sync from video h/w (##) + mov addr, base ' -8 working copy + mov vscl, hvis ' -4 1/4 + + rdlong pal+$00, addr ' +0 = + cmp pal+$00, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$01, addr ' +0 = + cmp pal+$01, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$02, addr ' +0 = + cmp pal+$02, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$03, addr ' +0 = + cmp pal+$03, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$04, addr ' +0 = + cmp pal+$04, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$05, addr ' +0 = + cmp pal+$05, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$06, addr ' +0 = + cmp pal+$06, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$07, addr ' +0 = + cmp pal+$07, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$08, addr ' +0 = + cmp pal+$08, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$09, addr ' +0 = + cmp pal+$09, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$0A, addr ' +0 = + cmp pal+$0A, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$0B, addr ' +0 = + cmp pal+$0B, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$0C, addr ' +0 = + cmp pal+$0C, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$0D, addr ' +0 = + cmp pal+$0D, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$0E, addr ' +0 = + cmp pal+$0E, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$0F, addr ' +0 = + cmp pal+$0F, #%%3210 ' +8 WHOP + add addr, #4 ' -4 0..63 + + rdlong pal+$10, addr ' +0 = + cmp pal+$10, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$11, addr ' +0 = + cmp pal+$11, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$12, addr ' +0 = + cmp pal+$12, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$13, addr ' +0 = + cmp pal+$13, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$14, addr ' +0 = + cmp pal+$14, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$15, addr ' +0 = + cmp pal+$15, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$16, addr ' +0 = + cmp pal+$16, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$17, addr ' +0 = + cmp pal+$17, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$18, addr ' +0 = + cmp pal+$18, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$19, addr ' +0 = + cmp pal+$19, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$1A, addr ' +0 = + cmp pal+$1A, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$1B, addr ' +0 = + cmp pal+$1B, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$1C, addr ' +0 = + cmp pal+$1C, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$1D, addr ' +0 = + cmp pal+$1D, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$1E, addr ' +0 = + cmp pal+$1E, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$1F, addr ' +0 = + cmp pal+$1F, #%%3210 ' +8 WHOP + add addr, #4 ' -4 64..127 + + rdlong pal+$20, addr ' +0 = + cmp pal+$20, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$21, addr ' +0 = + cmp pal+$21, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$22, addr ' +0 = + cmp pal+$22, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$23, addr ' +0 = + cmp pal+$23, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$24, addr ' +0 = + cmp pal+$24, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$25, addr ' +0 = + cmp pal+$25, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$26, addr ' +0 = + cmp pal+$26, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$27, addr ' +0 = + cmp pal+$27, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$28, addr ' +0 = + cmp pal+$28, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$29, addr ' +0 = + cmp pal+$29, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$2A, addr ' +0 = + cmp pal+$2A, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$2B, addr ' +0 = + cmp pal+$2B, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$2C, addr ' +0 = + cmp pal+$2C, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$2D, addr ' +0 = + cmp pal+$2D, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$2E, addr ' +0 = + cmp pal+$2E, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$2F, addr ' +0 = + cmp pal+$2F, #%%3210 ' +8 WHOP + add addr, #4 ' -4 128..191 + + rdlong pal+$30, addr ' +0 = + cmp pal+$30, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$31, addr ' +0 = + cmp pal+$31, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$32, addr ' +0 = + cmp pal+$32, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$33, addr ' +0 = + cmp pal+$33, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$34, addr ' +0 = + cmp pal+$34, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$35, addr ' +0 = + cmp pal+$35, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$36, addr ' +0 = + cmp pal+$36, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$37, addr ' +0 = + cmp pal+$37, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$38, addr ' +0 = + cmp pal+$38, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$39, addr ' +0 = + cmp pal+$39, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$3A, addr ' +0 = + cmp pal+$3A, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$3B, addr ' +0 = + cmp pal+$3B, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$3C, addr ' +0 = + cmp pal+$3C, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$3D, addr ' +0 = + cmp pal+$3D, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$3E, addr ' +0 = + cmp pal+$3E, #%%3210 ' +8 WHOP + add addr,#4 ' -4 + rdlong pal+$3F, addr ' +0 = + cmp pal+$3F, #%%3210 ' +8 WHOP + add addr, #4 ' -4 192..255 + + rdlong pal+$40, addr ' +0 = + cmp pal+$40, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$41, addr ' +0 = + cmp pal+$41, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$42, addr ' +0 = + cmp pal+$42, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$43, addr ' +0 = + cmp pal+$43, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$44, addr ' +0 = + cmp pal+$44, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$45, addr ' +0 = + cmp pal+$45, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$46, addr ' +0 = + cmp pal+$46, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$47, addr ' +0 = + cmp pal+$47, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$48, addr ' +0 = + cmp pal+$48, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$49, addr ' +0 = + cmp pal+$49, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$4A, addr ' +0 = + cmp pal+$4A, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$4B, addr ' +0 = + cmp pal+$4B, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$4C, addr ' +0 = + cmp pal+$4C, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$4D, addr ' +0 = + cmp pal+$4D, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$4E, addr ' +0 = + cmp pal+$4E, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$4F, addr ' +0 = + cmp pal+$4F, #%%3210 ' +8 WHOP + add addr, #4 ' -4 256..319 + + rdlong pal+$50, addr ' +0 = + cmp pal+$50, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$51, addr ' +0 = + cmp pal+$51, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$52, addr ' +0 = + cmp pal+$52, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$53, addr ' +0 = + cmp pal+$53, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$54, addr ' +0 = + cmp pal+$54, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$55, addr ' +0 = + cmp pal+$55, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$56, addr ' +0 = + cmp pal+$56, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$57, addr ' +0 = + cmp pal+$57, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$58, addr ' +0 = + cmp pal+$58, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$59, addr ' +0 = + cmp pal+$59, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$5A, addr ' +0 = + cmp pal+$5A, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$5B, addr ' +0 = + cmp pal+$5B, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$5C, addr ' +0 = + cmp pal+$5C, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$5D, addr ' +0 = + cmp pal+$5D, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$5E, addr ' +0 = + cmp pal+$5E, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$5F, addr ' +0 = + cmp pal+$5F, #%%3210 ' +8 WHOP + add addr, #4 ' -4 320..383 + + rdlong pal+$60, addr ' +0 = + cmp pal+$60, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$61, addr ' +0 = + cmp pal+$61, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$62, addr ' +0 = + cmp pal+$62, #%%3210 ' +8 WHOP + add addr, #4 ' -4 + rdlong pal+$63, addr ' +0 = + cmp pal+$63, #%%3210 ' +8 WHOP + add lcnt, #1 ' -4 384..399, line has been fetched + + jmpret $, #suffix wc,nr ' +0 = chain call (carry clear) + +' Odd line emitter (emit only). + +emit_1 waitcnt cnt, #0 ' re-sync after back porch (%%) + +' At this point the video h/w is driving the sync lines low (colour %%2). +' outa has taken over long ago so we can switch configuration here. + + mov vcfg, vcfg_norm ' -12 disconnect sync from video h/w (##) + movd :vid, #pal+$00 ' -8 colour buffer + mov vscl, hvis ' -4 1/4 + + mov ecnt, #100 -1 ' +0 = quad pixel count (last one separate) + test $, #1 wc ' +4 set carry +:vid cmp 0-0, #%%3210 ' +8 WHOP + addx $-1, #511{+C} ' -4 + djnz ecnt, #:vid -1 ' +0 = maintain 16 cycle loop + + cmp pal+$63, #%%3210 ' +8 WHOP + + jmpret zero, #suffix wc,nr ' -4 chain call (carry set) + +' initialised data and/or presets + +idle long (hv_idle & $00FF) << (sgrp * 8) +sync long (hv_idle ^ $0200) & $FFFF + +hvis long 1 << 12 | 4 ' 1/4 +hs_f long 1 << 12 | 20 ' 1/20 +slow long 32 << 12 | 108 ' 32/108 +full long 32 << 12 | 528 ' 32/528 + +vcfg_norm long %0_01_1_00_000 << 23 | vgrp << 9 | vpin +vcfg_sync long %0_01_1_00_000 << 23 | sgrp << 9 | %11 + +mask long vpin << (vgrp * 8) | %11 << (sgrp * 8) + +blnk long -4 +base long +0 + +' Stuff below is re-purposed for temporary storage. + +setup rdlong cnt, #0 ' +0 = clkfreq + + add blnk, par ' +8 frame indicator + neg href, cnt ' -4 hub window reference + add base, par ' +0 = scanline buffer + +' Upset video h/w and relatives. + + movi ctra, #%0_00001_101 ' PLL, VCO/4 + movi frqa, #%0001_00000 ' 5MHz * 16 / 4 = 20MHz + + mov vscl, hvis ' 1/4 + mov vcfg, vcfg_sync ' VGA, 4 colour mode + + shr cnt, #10 ' ~1ms + add cnt, cnt + waitcnt cnt, #0 ' PLL needs to settle + +' The first issued waitvid is a bit of a gamble if we don't know where the WHOP +' is located. We could do some fancy math or simply issue a dummy waitvid. + + waitvid zero, #0 ' dummy (first one is unpredictable) + waitvid zero, #0 ' point of reference + + add href, cnt ' get current sync slot + shr href, #2 ' 4 system clocks per pixel + neg href, href ' | + and href, #%11 ' calculate adjustment + +' WHOP is reasonably far away so we can update vscl without re-sync. + + add vscl, href ' | + waitvid zero, #0 ' stretch frame + sub vscl, href ' | + waitvid zero, #0 ' restore frame + +' Setup complete, do the heavy lifting upstairs ... + + jmp %%0 ' return + +' uninitialised data and/or temporaries + + org setup + +href res 1 ' hub window reference + +ecnt res 1 ' element count +lcnt res 1 ' line counter +scnt res 1 ' scanlines +addr res 1 ' colour buffer reference + +pal res 100 ' colour buffer + +tail fit + +DAT ' translation table + +__table word (@__names - @__table)/2 + + word res_x + word res_y + +__names byte "res_x", 0 + byte "res_y", 0 + +CON + zero = $1F0 ' par (dst only) + vpin = $0FC ' pin group mask + vgrp = 1 ' pin group + sgrp = 1 ' pin group sync + hv_idle = $01010101 * %00 {%hv} ' h/v sync inactive + + res_x = 400 ' | + res_y = 300 ' UI support + +DAT diff --git a/source/boing/boing-bel-feeder.spin b/source/boing/boing-bel-feeder.spin new file mode 100644 index 0000000..a33a474 --- /dev/null +++ b/source/boing/boing-bel-feeder.spin @@ -0,0 +1,762 @@ +'' +'' VGA scanline driver 400x300 - image feeder +'' +'' Based on "Ball" demo for Gameduino +'' Copyright (c) 2011 by James Bowman +'' +'' Author: Marko Lukat +'' Last modified: 2013/01/03 +'' Version: 0.6 +'' +'' 20121225: adjusted palette (brighter) +'' 20121226: 256 colour setup (RRGGBBgr) +'' 20130103: minor tweak to palette table +'' +OBJ + system: "boing-bel-corecon" + +VAR + long guard_before, buffer[BSIZE/4], guard_after + byte image[BSIZE*BSIZE] + + long GD_srcp, GD_mask, GD_stack[32] + +PUB null +'' This is not a top level object. + +PUB init(ID, mailbox) + + long[mailbox][-3] := @image{0} >< 32 | @buffer{0} + return system.launch(ID, @entry, mailbox) + +PUB uncompress(wait{boolean}) + + ifnot wait + if cognew(GD_uncompress(256, @ball), @GD_stack{0}) +1 + return + + GD_uncompress(256, @ball) + +PRI GD_uncompress(offs, srcp) | b_off, b_len, minlen, offset + + GD_srcp := srcp + GD_mask := $01010101 + + b_off := GD_getn(4) + b_len := GD_getn(4) + minlen := GD_getn(2) + + repeat GD_getn(16) + ifnot GD_get1 + image[GD_translate(offs++)] := !GD_getn(8) + next + offset := offs - GD_getn(b_off) - 1 + repeat GD_getn(b_len) + minlen + image[GD_translate(offs++)] := image[GD_translate(offset++)] + +PRI GD_getn(n) : r + + repeat n + r := r << 1 | GD_get1 + +PRI GD_get1 : r + + if byte[GD_srcp] & GD_mask + r := 1 + + if (GD_mask <-= 1) == $01010101 + GD_srcp++ + +PRI GD_translate(offs) : r + + if offs => constant(256*(5+1)) + offs += 256 + if offs => constant(256*(40+2)) + offs += 256 + + r := offs.byte[1] + return (r / 7)*constant(16*112) + (r // 7) << 4 + offs & 15 + (offs & $F0)*7 + +DAT org 0 ' image feeder + +entry jmpret $, #setup ' once + + rdlong indx, blnk ' | + cmpsub indx, scry wz ' | + if_ne jmp #$-2 ' waiting for last line to be fetched + +' The foreground renderer starts reading the colour buffer after 26 sync lines +' and 161+5 hub windows. We have to be done before that happens. Using the assumed +' hubop (161 hub windows) as reference we simply go back by 112*2+4 hub windows. + + mov cnt, cnt + add cnt, $+1 + long 13{18} + 14 + 132*16*26 + 16*(161 - 2) - 228*16 + +loop waitcnt cnt, one ' initial sync point +' cogid $ nr ' assumed hubop + + call #transfer ' palette translation + + add indx, #1 ' line done, advance + cmpsub indx, scry wz ' optionally wrap line index + if_nz jmp #loop + +' per frame updates (during the first frame mask is off-screen) + + rdlong temp, blnk ' | + cmp temp, scry wz ' | + if_ne jmp #$-2 ' wait for ?/scry transition + + rdword msky, crdy ' | + shl msky, #16 ' | + sar msky, #16 ' update and sign-extend mask coordinate + + maxs msky, scry ' reasonable limit (off-screen) + mov mskc, msky ' | + add mskc, #BSIZE -1 ' bounding box setup + +one long 132*16*2 ' skip two scan lines +two long 132*16*28 ' skip all sync lines + + call #update ' update palette + + add cnt, two + jmp #loop + +' support code + +transfer cmps indx, msky wc ' | + if_nc cmps mskc, indx wc ' | + if_c jmp transfer_ret ' vertical bounds check + + rdlong addr, feed ' crs/dst + mov arg0, addr + rev arg0, #{32-}0 ' tsd/src + + mov temp, indx ' + sub temp, msky ' active row + + mov arg1, temp + shl arg1, #3 ' *8 + sub arg1, temp ' *7 + shl arg1, #4 ' *112 + + add arg0, arg1 ' apply offset + + mov ecnt, #BSIZE + + rdbyte phsb, arg0 + movd $+2, phsb + add arg0, #1 + wrbyte phsb, addr + add addr, #1 + djnz ecnt, #$-5 ' translate index to colour + +transfer_ret ret + +update mov arg0, #32*7 ' slot 7 + + call #cycle ' | + cmpsub arg0, #32*1 wz ' | + if_nz jmp #$-2 ' for all slots except 0 + +update_ret ret + +cycle mov arg1, arg0 ' | + add arg1, #palette ' apply base + + movd :cy2, arg1 ' head + add arg1, #30 ' | + movs :cy1, arg1 ' | + add arg1, #1 ' | + movd :cy1, arg1 ' body + movs :cy0, arg1 ' tail + + mov ecnt, #32-1 + +:cy0 mov temp, 1-1 ' preserve last entry +:cy1 mov 1-1, 0-0 ' long rotate + sub $-1, d1s1 + djnz ecnt, #:cy1 + +:cy2 mov 0-0, temp ' close rotate +cycle_ret ret + +' initialised data and/or presets + +feed long -12 ' | +crdy long -6 ' | + ' quick access relative to par +blnk long -4 ' | +base long NEGX ' | + +d1s1 long |< 9 | 1 ' dst/src +/- 1 + + long 0[$ & 1] +palette long $00[32] ' unused/transparent + long $FF[16], $C1[16] ' 1: $F0 - %111_1 + long $FF[16], $C1[16] ' 2: $E0 %111_0 + long $FC[16], $C0[16] ' 3: $D0 %110_1 + long $FC[16], $C0[16] ' 4: $C0 %110_0 + long $AB[16], $81[16] ' 5: $B0 %101_1 + long $AB[16], $81[16] ' 6: $A0 %101_0 + long $A8[16], $80[16] ' 7: $90 - %100_1 + +' Stuff below is re-purposed for temporary storage. + +setup add crdy, par ' mask coordinate (%%) + add feed, par ' mask buffer location + + add base, par ' scanline buffer + add blnk, base wc ' frame indicator + + rdword indx, blnk wz ' (%%) + if_nz mov scry, indx wc ' (%%) + if_c_or_nz jmp #$-2 ' auto-detect res_y + +' The loop is only left once a non-zero value has been written to scry +' and indx transitions to zero afterwards. + + mov msky, scry ' move off-screen + + movi ctrb, #%0_11111_000 ' LOGIC always (relocation support) + mov frqb, #palette >> 1 ' | + + jmp %%0 ' return + + fit + +' uninitialised data and/or temporaries + + org setup + +scry res 1 ' must be 1st..4th (%%) +indx res 1 ' | + +addr res 1 ' scanline reference +ecnt res 1 ' element count + +mskc res 1 ' upper limit (inclusive) +mskx res 1 ' mask coordinates +msky res 1 ' signed 16bit + +arg0 res 1 +arg1 res 1 + +temp res 1 + +tail fit + +CON + zero = $1F0 ' par (dst only) + + BSIZE = 112 ' mask width/height (4n) + +DAT + +ball byte $c9, $a1, $dc, $f9, $0f, $e0, $41, $3c, $88, $07, $f1, $20, $1e, $c4, $83, $78 + byte $10, $0f, $e2, $41, $3c, $88, $07, $71, $ff, $06, $ed, $85, $f2, $20, $68, $d8 + byte $be, $5d, $5b, $c1, $df, $bf, $d1, $70, $60, $c7, $94, $8d, $e0, $6f, $d9, $bc + byte $59, $d3, $26, $4d, $18, $0b, $be, $d6, $2c, $99, $37, $63, $ca, $a4, $71, $63 + byte $46, $82, $8f, $15, $8b, $e6, $82, $83, $89, $e0, $68, $38, $78, $5b, $b1, $10 + byte $9c, $8d, $1a, $31, $6c, $28, $78, $da, $b4, $1c, $dc, $0d, $19, $0c, $1e, $36 + byte $82, $7b, $b8, $30, $68, $c0, $bf, $f5, $e0, $9a, $14, $82, $93, $fd, $6a, $1f + byte $c4, $83, $b8, $1d, $9b, $d6, $ad, $5a, $0e, $b6, $06, $82, $a1, $35, $2b, $96 + byte $2c, $5a, $08, $5e, $86, $ec, $d9, $0e, $8b, $c1, $ca, $9c, $d9, $e0, $61, $d0 + byte $6e, $b0, $ab, $11, $66, $4c, $07, $eb, $28, $61, $39, $4a, $98, $0f, $07, $c1 + byte $c1, $94, $1d, $5b, $36, $ac, $25, $8a, $38, $18, $ac, $5b, $40, $1c, $b2, $6c + byte $c9, $42, $38, $09, $0e, $c6, $c3, $41, $e2, $0a, $ee, $c6, $8c, $96, $6a, $7b + byte $76, $e3, $62, $b8, $0c, $ee, $76, $6c, $db, $b2, $69, $c3, $7a, $70, $30, $d2 + byte $22, $0c, $84, $03, $3b, $c1, $25, $6e, $5a, $69, $11, $c1, $3d, $38, $58, $b5 + byte $62, $d9, $80, $fd, $e0, $19, $8d, $83, $b3, $a5, $e0, $6e, $2d, $5a, $5a, $d6 + byte $a4, $29, $dc, $59, $0f, $4e, $9a, $4b, $87, $ad, $8e, $59, $1c, $22, $45, $8a + + byte $ca, $90, $d6, $cb, $b2, $e9, $ad, $b0, $0e, $97, $43, $15, $d8, $1c, $66, $8b + byte $dc, $3a, $cc, $06, $f6, $83, $7d, $e5, $8d, $b2, $c1, $32, $1c, $a6, $c3, $5a + byte $1c, $55, $ec, $05, $47, $dd, $17, $a3, $16, $46, $9d, $e0, $a0, $a7, $0c, $04 + byte $cb, $70, $a7, $37, $67, $ea, $cc, $04, $d1, $3c, $5c, $e8, $b2, $a9, $d3, $48 + byte $70, $29, $01, $7a, $83, $a3, $2d, $9d, $36, $82, $b3, $7e, $fb, $fa, $ec, $da + byte $d1, $6d, $3b, $3c, $e8, $b8, $17, $03, $50, $41, $70, $d4, $13, $ad, $74, $e8 + byte $d0, $de, $20, $34, $5a, $50, $6f, $4f, $6f, $78, $d4, $15, $9e, $b4, $59, $0c + byte $8e, $e6, $d4, $99, $55, $a3, $3a, $5a, $85, $87, $e0, $a1, $c1, $bc, $7a, $75 + byte $6a, $cd, $04, $0f, $53, $2a, $55, $da, $d0, $6e, $4d, $9b, $86, $68, $61, $4e + byte $6d, $78, $30, $ad, $4a, $95, $4a, $15, $ca, $95, $2b, $d3, $fa, $db, $83, $e8 + byte $99, $7c, $45, $a1, $dd, $5e, $ff, $6e, $14, $46, $43, $ec, $9e, $56, $6e, $4c + byte $a9, $62, $43, $0a, $ed, $87, $a4, $52, $bc, $34, $15, $19, $54, $50, $28, $74 + byte $87, $88, $cb, $50, $31, $ac, $69, $d5, $b2, $26, $34, $9a, $af, $19, $b6, $75 + byte $6a, $6f, $10, $b9, $e0, $34, $6a, $b2, $a8, $a1, $30, $a8, $09, $1e, $3a, $0a + byte $86, $75, $6d, $e1, $b9, $74, $54, $42, $93, $2a, $4a, $a6, $55, $2d, $a7, $23 + byte $3c, $55, $0a, $d5, $25, $43, $7b, $b8, $d0, $6a, $45, $b3, $26, $8d, $e1, $a1 + + byte $56, $d4, $82, $e0, $11, $2d, $c2, $4b, $7c, $a8, $0d, $6a, $6a, $a6, $b6, $e0 + byte $90, $0e, $c2, $63, $2b, $0c, $0f, $c1, $2b, $19, $bc, $ca, $e8, $10, $fc, $c2 + byte $73, $b2, $0c, $3e, $22, $55, $64, $cd, $5f, $10, $9e, $d5, $aa, $11, $1d, $3d + byte $44, $68, $89, $57, $c1, $5b, $8c, $6a, $d5, $f1, $b3, $ff, $07, $f1, $20, $1e + byte $c4, $83, $78, $10, $0f, $e2, $41, $3c, $88, $07, $f1, $20, $a2, $4d, $73, $08 + byte $0f, $c2, $d6, $b4, $68, $52, $1f, $e2, $83, $a0, $72, $a5, $9a, $35, $aa, $53 + byte $15, $e2, $fd, $07, $0f, $25, $8a, $34, $88, $0d, $e1, $c1, $43, $99, $12, $c5 + byte $0a, $f5, $ab, $51, $a9, $24, $a2, $de, $04, $25, $82, $15, $2a, $90, $27, $5b + byte $44, $08, $15, $1e, $3e, $05, $29, $d0, $a7, $57, $96, $0e, $21, $11, $3a, $7c + byte $08, $55, $ac, $48, $a0, $7e, $b9, $ba, $65, $6a, $13, $2c, $27, $7d, $29, $0b + byte $de, $f2, $f4, $c8, $92, $a1, $55, $52, $08, $54, $2e, $4c, $a9, $60, $41, $0a + byte $05, $c8, $8b, $80, $d2, $a5, $48, $94, $5d, $ff, $83, $78, $10, $0f, $c2, $36 + byte $82, $7b, $10, $b6, $69, $25, $f8, $07, $21, $5b, $56, $2c, $06, $ff, $20, $64 + byte $d5, $92, $f9, $e0, $1f, $04, $ad, $59, $b2, $60, $36, $f8, $07, $01, $e3, $8a + byte $0d, $d8, $b3, $13, $fc, $fd, $9b, $54, $62, $d0, $be, $5d, $dd, $c1, $df, $bf + byte $51, $43, $fa, $f5, $da, $d6, $15, $fc, $a3, $85, $82, $68, $a1, $cb, $66, $f0 + + byte $53, $65, $c4, $60, $78, $d0, $ad, $b3, $f8, $1b, $53, $d4, $0b, $ec, $84, $07 + byte $ed, $e1, $57, $85, $11, $85, $f6, $e3, $85, $4e, $1d, $da, $82, $6f, $78, $d4 + byte $ab, $47, $97, $0d, $ed, $c1, $57, $45, $d6, $d0, $67, $27, $5e, $e8, $b0, $a6 + byte $35, $fc, $18, $55, $94, $0c, $c2, $83, $8e, $f0, $a0, $c5, $86, $65, $0b, $e6 + byte $cc, $98, $32, $61, $dc, $98, $11, $c3, $86, $0c, $1a, $b0, $6f, $2f, $38, $9b + byte $0c, $0e, $46, $83, $8b, $5d, $8b, $e1, $32, $38, $19, $09, $d7, $76, $ed, $98 + byte $37, $6b, $da, $a4, $09, $63, $46, $a3, $65, $34, $b4, $17, $3c, $82, $43, $3c + byte $0c, $4e, $f1, $28, $38, $d8, $4e, $fa, $e1, $d1, $ae, $9e, $e6, $61, $cb, $a6 + byte $75, $6b, $e1, $21, $1e, $5d, $0c, $3b, $7a, $74, $d7, $88, $82, $61, $55, $8b + byte $65, $4d, $1a, $15, $e8, $d7, $17, $1e, $6d, $b5, $80, $82, $61, $45, $b3, $25 + byte $8b, $1a, $cc, $9b, $53, $ab, $26, $5c, $b4, $40, $6d, $e1, $41, $b3, $46, $0d + byte $ea, $d5, $a9, $55, $6b, $46, $b5, $2a, $95, $2a, $b4, $6b, $0d, $8f, $1a, $2d + byte $a8, $0f, $8f, $aa, $4d, $a9, $0c, $1e, $0d, $22, $5a, $84, $67, $35, $aa, $c3 + byte $93, $f2, $68, $99, $0c, $a2, $53, $f0, $88, $16, $e1, $41, $b9, $16, $cd, $c1 + byte $d1, $7c, $bc, $08, $af, $c1, $23, $6b, $86, $37, $15, $2a, $84, $2b, $0b, $4f + byte $e9, $30, $5a, $46, $07, $11, $ca, $95, $29, $ab, $89, $15, $c1, $86, $8d, $4a + + byte $a0, $55, $4b, $69, $d2, $68, $c7, $76, $70, $b0, $19, $1c, $0a, $85, $55, $2b + byte $71, $42, $53, $e9, $b0, $1d, $3c, $c3, $a5, $b6, $f0, $90, $3b, $d2, $84, $05 + byte $0d, $c1, $49, $7b, $cd, $68, $98, $49, $c2, $62, $11, $d4, $b5, $33, $36, $45 + byte $29, $28, $4c, $85, $4b, $7d, $8b, $b2, $16, $ad, $72, $67, $b4, $c8, $12, $36 + byte $37, $41, $b4, $48, $9b, $b9, $b3, $36, $a9, $d3, $b1, $0b, $ad, $b6, $4c, $4d + byte $d1, $ba, $72, $e8, $b0, $ae, $2d, $5a, $95, $a6, $ca, $18, $3c, $d2, $66, $b4 + byte $0e, $af, $6a, $2b, $82, $52, $a5, $2d, $23, $3c, $8b, $57, $27, $6e, $62, $04 + byte $4f, $25, $4a, $14, $2b, $d2, $a8, $51, $82, $fa, $89, $25, $46, $59, $78, $08 + byte $8e, $82, $14, $2a, $50, $a0, $5e, $9c, $3a, $b1, $6a, $82, $a7, $10, $25, $82 + byte $15, $29, $54, $28, $40, $bf, $7c, $7d, $72, $d5, $8a, $51, $1d, $de, $82, $87 + byte $be, $03, $a0, $e7, $00, $08, $0d, $17, $8a, $a3, $45, $78, $d4, $2f, $4f, $ae + byte $5c, $39, $b2, $65, $ef, $01, $75, $6b, $69, $6d, $8e, $8b, $e1, $a8, $d4, $fc + byte $38, $5a, $5a, $26, $55, $28, $cf, $5a, $c1, $c1, $6c, $2e, $30, $bd, $95, $82 + byte $c7, $b4, $50, $aa, $c4, $dc, $5a, $dc, $aa, $45, $f9, $72, $2e, $ed, $78, $25 + byte $4c, $a9, $10, $c5, $6a, $a2, $c5, $19, $12, $19, $af, $a3, $83, $e0, $e0, $10 + byte $5e, $b6, $86, $30, $65, $79, $23, $1f, $84, $27, $51, $8f, $33, $1d, $85, $c7 + + byte $e8, $a1, $46, $b4, $2a, $55, $d1, $22, $3c, $0a, $0b, $0f, $f1, $41, $50, $8d + byte $c8, $9a, $2a, $83, $c3, $95, $a8, $13, $c1, $a1, $49, $c4, $0b, $51, $57, $20 + byte $1d, $c6, $ab, $f0, $a8, $48, $75, $74, $10, $29, $32, $3c, $09, $cd, $86, $e1 + byte $41, $a0, $ea, $f0, $94, $8e, $85, $08, $11, $2c, $48, $91, $c0, $f0, $a0, $32 + byte $bc, $8d, $0e, $41, $5d, $42, $54, $36, $50, $21, $42, $78, $bc, $14, $1a, $1e + byte $c2, $87, $40, $81, $ba, $64, $ca, $0c, $0e, $ca, $85, $55, $c5, $64, $19, $1e + byte $04, $44, $82, $b5, $a5, $7e, $6d, $94, $c1, $a8, $10, $17, $96, $e1, $3c, $58 + byte $1b, $ea, $96, $66, $96, $6c, $14, $8a, $33, $e6, $da, $98, $06, $4b, $a1, $0a + byte $b6, $ca, $bd, $b0, $0e, $14, $ac, $4d, $bd, $7a, $3a, $53, $52, $58, $86, $02 + byte $83, $87, $bc, $65, $b0, $34, $64, $c9, $52, $19, $3d, $14, $15, $04, $05, $02 + byte $f6, $82, $de, $f0, $a1, $3b, $2b, $ca, $10, $1e, $2d, $c2, $e3, $51, $94, $13 + byte $3e, $75, $ca, $d0, $21, $3d, $3c, $2a, $08, $0e, $f2, $f4, $ca, $d1, $2d, $3b + byte $7c, $c8, $90, $ae, $3d, $78, $5c, $e9, $e0, $21, $3b, $3e, $84, $0f, $e9, $d2 + byte $2a, $44, $78, $90, $9f, $2c, $c3, $87, $ac, $2a, $11, $3e, $82, $87, $80, $e8 + byte $72, $25, $82, $87, $8c, $e0, $15, $9e, $e5, $ea, $09, $1e, $f1, $31, $7c, $97 + byte $8d, $e8, $14, $1f, $65, $06, $87, $f8, $21, $20, $1f, $06, $9f, $f8, $2c, $2d + + byte $38, $24, $cb, $2f, $14, $5f, $b8, $05, $8f, $aa, $55, $8d, $a2, $83, $0c, $ee + byte $d2, $a4, $0e, $05, $a5, $0d, $51, $41, $4c, $d0, $2d, $4b, $86, $36, $c9, $12 + byte $44, $4d, $89, $c9, $51, $b2, $62, $42, $0c, $90, $2e, $45, $92, $b8, $29, $70 + byte $33, $26, $63, $22, $c8, $11, $32, $a5, $4b, $8d, $00, $97, $62, $76, $b6, $84 + byte $e0, $91, $10, $65, $48, $8b, $00, $4b, $70, $35, $a6, $4a, $b9, $05, $22, $7f + byte $48, $e5, $fc, $28, $83, $87, $c2, $e0, $25, $27, $01, $a4, $0f, $29, $19, $e2 + byte $34, $0a, $0c, $be, $32, $b8, $05, $4f, $29, $92, $05, $05, $1f, $d9, $3c, $13 + byte $00, $d7, $f0, $11, $3c, $24, $49, $0c, $5f, $7c, $64, $cb, $e4, $91, $21, $a4 + byte $4a, $0d, $5e, $12, $c4, $f3, $ab, $99, $bc, $2a, $00, $b7, $e0, $27, $8e, $6d + byte $f8, $08, $de, $52, $c2, $27, $47, $0e, $e2, $d9, $89, $15, $c3, $5a, $16, $4f + byte $e9, $e1, $23, $38, $70, $8e, $1f, $d1, $83, $1d, $db, $e0, $21, $8a, $25, $f7 + byte $e0, $c1, $45, $b2, $24, $4e, $12, $39, $b0, $17, $27, $96, $0d, $6b, $56, $2c + byte $45, $30, $4b, $0e, $e1, $21, $78, $48, $60, $1f, $3d, $d8, $88, $0e, $1e, $2c + byte $98, $71, $8d, $1e, $c1, $21, $7e, $b1, $0d, $5f, $2c, $98, $fb, $0f, $e0, $41 + byte $44, $44, $f0, $0f, $22, $62, $85, $85, $f0, $20, $2c, $9e, $b5, $e0, $10, $1e + byte $84, $24, $88, $65, $19, $fc, $83, $90, $24, $f6, $62, $52, $7e, $f0, $e6, $20 + + byte $96, $15, $d3, $08, $1f, $04, $38, $4b, $64, $cf, $46, $04, $a3, $10, $ee, $9f + byte $8b, $24, $09, $6c, $59, $31, $0b, $fe, $fe, $a5, $70, $e2, $c0, $8e, $3d, $0b + byte $c6, $21, $9c, $0b, $67, $8e, $ec, $d9, $92, $62, $c6, $3f, $84, $6d, $88, $e0 + byte $c9, $9a, $05, $e1, $e0, $c7, $95, $73, $0c, $20, $c7, $86, $25, $33, $02, $21 + byte $94, $2b, $97, $e0, $91, $21, $48, $11, $8f, $60, $4c, $99, $50, $e2, $48, $9e + byte $6d, $0c, $60, $1a, $41, $83, $07, $63, $86, $ec, $c9, $91, $26, $49, $8c, $50 + byte $29, $0f, $02, $2a, $94, $28, $d4, $a7, $47, $b7, $4e, $1d, $da, $b4, $6a, $09 + byte $d5, $ca, $14, $29, $d0, $ab, $47, $97, $0e, $ed, $da, $b4, $68, $0e, $5e, $2a + byte $c3, $83, $7e, $bd, $e1, $49, $6a, $f0, $51, $ae, $58, $41, $74, $d0, $a5, $33 + byte $3c, $68, $d5, $ac, $29, $7c, $8a, $56, $aa, $28, $3c, $c8, $d6, $29, $43, $bb + byte $56, $29, $9a, $25, $05, $4f, $1d, $5a, $14, $ca, $8b, $17, $e1, $41, $5a, $b2 + byte $90, $a4, $31, $78, $4a, $d3, $a4, $41, $ac, $1a, $59, $c9, $42, $5a, $bc, $b8 + byte $12, $c1, $43, $b7, $56, $8d, $e2, $d5, $8a, $56, $29, $42, $58, $78, $90, $1c + byte $26, $82, $87, $0c, $29, $1a, $d5, $a9, $51, $a5, $52, $b9, $30, $a1, $8a, $9f + byte $60, $f0, $d0, $26, $39, $3a, $88, $11, $25, $42, $b8, $52, $25, $82, $15, $29 + byte $14, $10, $3c, $a4, $4a, $52, $2f, $56, $b5, $4a, $15, $e1, $41, $88, $60, $81 + + byte $0a, $e4, $fb, $d7, $15, $1d, $c4, $a9, $11, $25, $52, $b8, $32, $a5, $e1, $41 + byte $a0, $00, $fd, $fe, $65, $48, $96, $20, $4e, $8c, $aa, $e8, $20, $2c, $3c, $08 + byte $0a, $1e, $e1, $43, $7b, $7c, $14, $2d, $4a, $85, $70, $a1, $f1, $21, $5e, $c8 + byte $97, $e7, $5f, $9a, $24, $f1, $62, $45, $8b, $cc, $16, $42, $85, $84, $a7, $e0 + byte $21, $55, $a2, $f8, $74, $11, $1f, $a2, $ab, $bc, $06, $a1, $51, $83, $7a, $75 + byte $6a, $d5, $88, $2e, $10, $2a, $62, $41, $2a, $d0, $14, $1c, $c4, $07, $07, $31 + byte $aa, $55, $a9, $12, $19, $1c, $95, $09, $6d, $10, $e1, $41, $5c, $78, $16, $11 + byte $9e, $94, $46, $db, $f0, $11, $1e, $94, $d7, $44, $21, $1a, $25, $88, $0f, $2f + byte $d1, $49, $69, $cd, $48, $c6, $f1, $a1, $02, $44, $8b, $f0, $24, $44, $82, $7a + byte $71, $fd, $20, $1d, $86, $47, $61, $c9, $42, $89, $e2, $e0, $a0, $56, $6d, $78 + byte $69, $10, $25, $a1, $66, $84, $67, $51, $d9, $40, $44, $b4, $10, $a6, $34, $38 + byte $08, $ce, $07, $62, $c3, $73, $0b, $14, $da, $10, $05, $c9, $93, $ab, $47, $4c + byte $73, $a8, $1f, $c2, $93, $b5, $e0, $e0, $29, $47, $b7, $2c, $99, $f3, $42, $f8 + byte $f0, $88, $0f, $82, $83, $87, $3e, $b9, $72, $64, $07, $0f, $19, $32, $82, $a7 + byte $90, $01, $29, $28, $38, $06, $2f, $e9, $d2, $a4, $49, $4d, $96, $3d, $21, $3c + byte $cb, $94, $11, $3c, $a4, $4a, $95, $22, $59, $52, $f0, $8d, $0e, $c1, $53, $4a + + byte $f0, $e4, $28, $31, $63, $2a, $12, $a4, $50, $81, $00, $f9, $fa, $f4, $fd, $84 + byte $b4, $a8, $44, $88, $e2, $5d, $b1, $3a, $f5, $e7, $81, $b8, $a0, $5b, $b6, $ae + byte $45, $21, $28, $bc, $c8, $d3, $2b, $27, $4b, $ca, $0a, $af, $6b, $40, $6f, $78 + byte $96, $55, $10, $37, $c3, $61, $90, $57, $39, $c3, $43, $9e, $3c, $85, $97, $32 + byte $3c, $47, $47, $5d, $32, $2b, $84, $c2, $53, $a9, $2f, $59, $c9, $0e, $8f, $32 + byte $b3, $41, $78, $c8, $06, $d1, $31, $59, $97, $81, $12, $11, $1e, $a3, $83, $dc + byte $da, $13, $bc, $04, $84, $f7, $d6, $11, $3c, $e2, $55, $78, $eb, $5c, $d1, $22 + byte $bc, $25, $4b, $9e, $3c, $a4, $07, $7f, $d9, $bc, $c2, $13, $f7, $64, $cb, $47 + byte $36, $ef, $e0, $10, $1e, $c2, $47, $b2, $e0, $2f, $8f, $5f, $3a, $08, $1e, $b2 + byte $78, $c9, $4c, $16, $dc, $b9, $73, $90, $9f, $2c, $f9, $86, $c7, $e8, $10, $9e + byte $b8, $57, $08, $1d, $3a, $a4, $4b, $3f, $13, $83, $b3, $2a, $08, $8c, $17, $91 + byte $70, $1a, $ce, $03, $29, $cb, $28, $78, $ea, $94, $19, $1e, $83, $c3, $3c, $9c + byte $57, $c9, $22, $61, $84, $07, $6d, $e1, $71, $1e, $04, $0f, $89, $12, $25, $c8 + byte $5f, $8b, $6b, $7b, $19, $4a, $0a, $9e, $e2, $d7, $52, $74, $0d, $1e, $12, $38 + byte $04, $8f, $74, $70, $14, $b7, $66, $74, $d8, $06, $12, $d8, $07, $ef, $a3, $28 + byte $85, $b3, $24, $4e, $f1, $22, $3c, $04, $cf, $f0, $c8, $25, $59, $85, $07, $0e + + byte $e1, $43, $5c, $74, $e4, $9a, $0d, $b8, $84, $27, $8e, $c1, $81, $3d, $3b, $ee + byte $dc, $92, $05, $d7, $f0, $10, $bc, $c2, $83, $f8, $e0, $f1, $06, $83, $43, $78 + byte $90, $1c, $2f, $38, $72, $e0, $10, $1c, $c4, $85, $0f, $a9, $c1, $23, $59, $47 + byte $47, $f1, $ec, $d8, $26, $8b, $f8, $10, $9e, $38, $85, $e7, $e0, $11, $1f, $a2 + byte $13, $27, $49, $e9, $92, $7d, $74, $08, $9f, $5c, $b9, $86, $f7, $e0, $c1, $96 + byte $ed, $36, $97, $c5, $b3, $0d, $70, $cf, $1a, $e3, $69, $3a, $f0, $5e, $16, $d3 + byte $4a, $3a, $37, $ae, $d3, $e2, $2e, $5c, $a5, $79, $c1, $43, $46, $78, $90, $16 + byte $bc, $f8, $ca, $99, $0f, $f3, $52, $c6, $3a, $08, $0f, $52, $d9, $8b, $bb, $8b + byte $d1, $29, $3e, $70, $8f, $8e, $52, $c5, $65, $04, $31, $fb, $88, $a7, $4c, $1e + byte $75, $31, $6b, $88, $13, $c7, $56, $0c, $1b, $d1, $ac, $d2, $65, $f0, $8c, $1e + byte $5c, $c2, $83, $d8, $e0, $c0, $5a, $14, $4b, $96, $2c, $a4, $27, $87, $a2, $19 + byte $9e, $58, $b3, $66, $25, $32, $78, $30, $67, $1e, $1e, $a2, $07, $bb, $f0, $c0 + byte $26, $3c, $b0, $0a, $0e, $2c, $98, $33, $63, $c6, $94, $09, $17, $b6, $d1, $89 + byte $55, $f0, $23, $c2, $98, $2d, $9b, $f0, $10, $1d, $e2, $23, $73, $e2, $cc, $88 + byte $86, $8f, $e0, $1d, $5e, $a2, $07, $53, $a2, $e1, $2b, $59, $b2, $22, $c9, $82 + byte $04, $73, $62, $e1, $83, $09, $13, $c2, $d1, $81, $74, $74, $09, $1e, $e1, $21 + + byte $38, $04, $4f, $d6, $a4, $c2, $73, $7c, $8a, $0e, $8c, $b9, $70, $59, $8a, $4b + byte $62, $4e, $64, $8e, $c8, $99, $0b, $ae, $c4, $56, $d8, $c3, $59, $20, $78, $4f + byte $03, $ce, $4b, $71, $2e, $06, $4f, $52, $2c, $53, $45, $74, $5c, $1a, $7b, $b0 + byte $71, $90, $09, $5f, $c4, $c3, $07, $a7, $f0, $15, $1c, $c2, $37, $8b, $e0, $c5 + byte $71, $2f, $ac, $09, $b2, $79, $30, $73, $44, $0f, $ce, $f1, $89, $03, $f9, $e8 + byte $44, $ba, $51, $90, $20, $1e, $7c, $c2, $57, $7c, $20, $55, $19, $82, $07, $25 + byte $4e, $14, $c3, $43, $f0, $24, $13, $9e, $89, $45, $87, $e4, $40, $21, $38, $90 + byte $63, $9b, $1e, $c2, $43, $74, $60, $c6, $98, $52, $72, $a0, $10, $1f, $c8, $06 + byte $8f, $f0, $11, $1d, $89, $11, $66, $c4, $90, $40, $7e, $20, $47, $36, $7d, $90 + byte $0e, $5f, $c4, $08, $11, $0a, $1e, $04, $f8, $47, $c7, $f8, $11, $bc, $19, $31 + byte $22, $18, $1c, $e8, $d3, $a3, $1b, $1c, $c2, $2f, $c3, $e0, $41, $9f, $5f, $f0 + byte $a0, $43, $9b, $56, $f4, $21, $c8, $80, $40, $78, $a4, $1b, $3c, $69, $d2, $44 + byte $41, $1c, $19, $d1, $91, $c1, $90, $01, $3b, $36, $a4, $88, $13, $a1, $e7, $3f + byte $00, $ad, $c4, $18, $40, $8f, $0e, $29, $12, $44, $09, $06, $ef, $95, $c8, $88 + byte $01, $7d, $be, $b4, $49, $66, $09, $ba, $21, $88, $59, $f4, $20, $94, $00, $e8 + byte $d2, $a6, $49, $1c, $31, $fd, $e0, $45, $2c, $78, $30, $ca, $01, $c1, $93, $3a + + byte $15, $84, $38, $43, $20, $33, $22, $84, $09, $11, $a4, $9f, $1e, $68, $d1, $c0 + byte $4a, $09, $6f, $f0, $0c, $9f, $c1, $33, $05, $e0, $a2, $41, $0d, $33, $ba, $e0 + byte $c9, $34, $7c, $07, $0f, $5a, $38, $82, $07, $86, $18, $98, $3e, $a2, $17, $3d + byte $3c, $b4, $71, $62, $a3, $82, $11, $75, $04, $08, $de, $f8, $c3, $07, $6e, $9a + byte $d8, $b1, $60, $44, $1b, $7c, $e9, $e3, $a3, $83, $1b, $27, $76, $ac, $98, $c0 + byte $05, $6f, $44, $04, $c3, $07, $de, $e8, $11, $3c, $d1, $83, $f0, $1f, $bd, $10 + byte $86, $0f, $bc, $e1, $0b, $32, $7a, $50, $fe, $91, $12, $41, $4c, $08, $61, $f8 + byte $0c, $1e, $38, $b0, $62, $c6, $00, $3a, $7c, $20, $21, $8c, $88, $00, $7e, $7c + byte $e1, $13, $07, $34, $c8, $10, $c0, $04, $6f, $04, $c1, $07, $1b, $66, $8c, $60 + byte $fd, $cb, $96, $22, $51, $9c, $18, $51, $22, $84, $0b, $15, $22, $58, $90, $40 + byte $f9, $f2, $e4, $ca, $94, $22, $21, $f8, $09, $14, $10, $3c, $65, $48, $96, $20 + byte $56, $b4, $48, $11, $c2, $c2, $47, $78, $08, $5e, $d2, $25, $8b, $0f, $9e, $c2 + byte $83, $47, $74, $60, $28, $80, $bf, $3c, $be, $dc, $39, $89, $67, $2b, $9a, $a5 + byte $70, $66, $42, $18, $c7, $47, $7e, $72, $f9, $48, $93, $c4, $5e, $0c, $2b, $91 + byte $c9, $81, $89, $60, $46, $e1, $49, $0e, $b3, $e0, $25, $82, $b9, $d0, $e0, $11 + byte $9d, $e5, $08, $63, $28, $8e, $8d, $28, $16, $cc, $99, $0a, $61, $24, $90, $81 + + byte $fc, $e8, $c9, $8c, $21, $3f, $3e, $c1, $83, $19, $53, $c6, $af, $83, $01, $7f + byte $7e, $7c, $a3, $47, $f0, $e4, $c5, $42, $18, $d3, $f8, $10, $3e, $d2, $05, $1f + byte $de, $e1, $8b, $17, $0f, $6e, $e1, $2b, $3c, $06, $1f, $9e, $c1, $83, $0b, $e7 + byte $53, $11, $fc, $78, $f3, $e4, $ce, $2d, $78, $70, $a2, $10, $3c, $e8, $86, $0f + byte $e2, $0c, $e9, $f1, $a6, $c9, $9d, $1a, $17, $ca, $1c, $39, $b0, $67, $c7, $37 + byte $78, $32, $0a, $5e, $e1, $93, $23, $05, $f6, $e4, $d8, $92, $e1, $45, $92, $50 + byte $f6, $88, $1e, $d4, $a8, $70, $a6, $c8, $81, $3c, $3b, $32, $ac, $59, $c9, $91 + byte $23, $5b, $96, $4c, $19, $d2, $a5, $49, $93, $ca, $45, $32, $67, $49, $12, $25 + byte $06, $a7, $e0, $c1, $5d, $1a, $57, $a9, $52, $82, $83, $a4, $44, $20, $87, $b7 + byte $2c, $9e, $32, $c2, $27, $57, $29, $c1, $93, $a3, $44, $0e, $e1, $83, $57, $78 + byte $e4, $c6, $2d, $3a, $70, $96, $cc, $29, $3a, $70, $90, $2d, $9b, $57, $f8, $88 + byte $0f, $d1, $99, $53, $74, $e0, $c0, $3b, $3c, $c8, $e4, $51, $3c, $c2, $43, $72 + byte $08, $0e, $d1, $41, $7c, $78, $e2, $2e, $9d, $1b, $d7, $0a, $c0, $39, $78, $94 + byte $cc, $f0, $51, $2f, $c2, $43, $7c, $cc, $16, $f1, $81, $43, $c5, $48, $4f, $c1 + byte $83, $6b, $f8, $e4, $14, $1f, $d9, $b3, $4f, $16, $e1, $2b, $38, $b4, $40, $8e + byte $d1, $31, $78, $26, $8b, $f0, $19, $1f, $29, $05, $87, $86, $c0, $2e, $7c, $a4 + + byte $cb, $e4, $50, $3f, $a2, $53, $43, $0c, $1e, $34, $ba, $45, $7c, $a4, $cc, $89 + byte $62, $74, $6c, $09, $b4, $e2, $4b, $f8, $88, $0e, $14, $29, $04, $07, $72, $c1 + byte $83, $06, $75, $6e, $54, $e3, $4b, $74, $24, $c7, $92, $46, $fc, $a0, $c6, $95 + byte $0a, $65, $4a, $d1, $23, $3c, $8c, $c8, $02, $21, $fe, $50, $dc, $86, $c6, $28 + byte $b3, $71, $54, $41, $09, $e2, $d9, $89, $63, $cb, $a6, $57, $f0, $6a, $8d, $79 + byte $8a, $7d, $f0, $10, $1b, $3c, $44, $b3, $16, $95, $07, $f3, $54, $78, $16, $c3 + byte $7a, $0e, $88, $64, $c9, $42, $7a, $13, $dc, $04, $ec, $c4, $b2, $61, $13, $1c + byte $58, $05, $87, $57, $c1, $bc, $0c, $b0, $8f, $17, $d1, $21, $3c, $b2, $0c, $5e + byte $cc, $5e, $07, $3b, $76, $c1, $21, $3c, $84, $8f, $e0, $41, $82, $39, $73, $62 + byte $c1, $8f, $15, $a9, $e8, $cc, $8c, $28, $d3, $f0, $10, $5d, $48, $b2, $08, $1f + byte $d1, $81, $28, $13, $76, $64, $d9, $9c, $0a, $d2, $c9, $82, $65, $70, $20, $4e + byte $8c, $69, $f0, $8c, $4f, $a4, $d2, $65, $7c, $0a, $9e, $64, $1f, $06, $eb, $f0 + byte $40, $92, $24, $09, $16, $e1, $21, $3e, $30, $21, $12, $7c, $d2, $0d, $51, $a2 + byte $44, $88, $84, $07, $36, $e1, $81, $54, $78, $20, $41, $9c, $78, $ba, $24, $42 + byte $38, $ba, $24, $8b, $e8, $48, $2c, $3c, $12, $26, $4b, $86, $34, $e9, $f0, $10 + byte $3e, $c2, $43, $70, $08, $5e, $47, $f2, $ac, $0e, $89, $aa, $91, $2c, $96, $e2 + + byte $5e, $bc, $ca, $e3, $a2, $6e, $9e, $a9, $3b, $31, $0d, $ae, $02, $f9, $ae, $10 + byte $1e, $d8, $9c, $a9, $27, $45, $21, $3a, $92, $63, $9b, $2c, $82, $e7, $5e, $d8 + byte $1a, $7b, $23, $3c, $46, $47, $32, $4c, $f7, $44, $74, $e4, $18, $1e, $82, $07 + byte $39, $b2, $e1, $81, $4d, $85, $60, $4c, $f8, $2c, $06, $cf, $21, $19, $3c, $58 + byte $13, $61, $42, $98, $11, $21, $86, $04, $8f, $42, $ba, $08, $1f, $5d, $81, $34 + byte $93, $f0, $c0, $88, $20, $43, $02, $0c, $e8, $93, $eb, $13, $e1, $91, $74, $8d + byte $08, $4f, $04, $e8, $f3, $a7, $47, $8f, $2f, $99, $aa, $19, $1e, $08, $45, $87 + byte $f0, $48, $9f, $1e, $5d, $ba, $74, $e8, $d0, $26, $45, $38, $3e, $10, $24, $48 + byte $20, $7c, $84, $87, $e0, $49, $9b, $36, $2d, $c6, $e1, $21, $78, $d2, $0f, $0f + byte $e1, $23, $3c, $06, $8f, $74, $49, $90, $41, $78, $88, $ae, $b4, $70, $11, $26 + byte $14, $dd, $e3, $05, $6e, $5a, $b4, $a2, $3b, $5e, $3a, $78, $e2, $23, $ce, $b3 + byte $b9, $2e, $f6, $d1, $d9, $d8, $06, $f9, $80, $d0, $3e, $67, $36, $1d, $ab, $46 + byte $f0, $24, $75, $35, $48, $1c, $c3, $65, $9d, $2e, $f6, $21, $ab, $e8, $b8, $0e + byte $96, $75, $b2, $08, $1e, $e1, $61, $59, $30, $3f, $06, $c1, $77, $1f, $3d, $85 + byte $75, $79, $35, $92, $45, $3e, $dc, $06, $ac, $8f, $11, $b1, $f0, $1c, $bc, $ef + byte $66, $78, $0c, $de, $88, $08, $21, $4c, $17, $57, $fb, $18, $b5, $85, $aa, $79 + + byte $b6, $ee, $46, $74, $42, $42, $18, $31, $22, $82, $e1, $23, $3a, $23, $23, $86 + byte $94, $48, $f0, $20, $14, $3c, $10, $d0, $a2, $59, $0c, $90, $67, $8b, $af, $10 + byte $9e, $10, $22, $24, $40, $93, $26, $0d, $1a, $c4, $91, $21, $0b, $4f, $88, $93 + byte $05, $42, $04, $34, $71, $e2, $a0, $8e, $9d, $1a, $55, $a2, $48, $90, $c4, $0b + byte $44, $c1, $01, $01, $ce, $f0, $80, $1d, $1b, $36, $ac, $58, $a9, $60, $26, $1c + byte $1c, $82, $07, $7e, $9a, $38, $c2, $07, $36, $6a, $58, $b1, $60, $c1, $8c, $09 + byte $13, $46, $04, $08, $f0, $ef, $83, $65, $b4, $b4, $68, $45, $85, $38, $41, $6c + byte $99, $6c, $a5, $2c, $41, $23, $09, $60, $0d, $5e, $5b, $93, $0e, $6e, $da, $b8 + byte $c2, $47, $f0, $8a, $4e, $f4, $e7, $41, $70, $08, $1f, $38, $d2, $44, $f8, $d8 + byte $3a, $4b, $23, $3c, $a4, $85, $e0, $8d, $9f, $3e, $3e, $ba, $78, $a2, $47, $72 + byte $c0, $11, $3f, $f2, $40, $74, $c4, $47, $0f, $6f, $78, $c0, $1d, $3e, $a2, $63 + byte $f0, $40, $40, $00, $7f, $70, $08, $1f, $47, $22, $78, $17, $0e, $04, $f4, $f1 + byte $47, $47, $3c, $e1, $b1, $0e, $c4, $47, $28, $e1, $11, $5f, $74, $08, $5e, $55 + byte $00, $3b, $b4, $f0, $19, $1e, $82, $27, $ee, $f8, $0a, $15, $0b, $fe, $f8, $18 + byte $3e, $82, $43, $7c, $80, $11, $1e, $a1, $04, $0f, $7c, $d1, $05, $66, $74, $80 + byte $8e, $0d, $2a, $14, $cc, $d1, $05, $76, $ba, $84, $1e, $be, $20, $07, $0f, $bc + + byte $78, $e1, $44, $07, $58, $30, $a3, $63, $72, $80, $02, $39, $3a, $c0, $c5, $93 + byte $2e, $60, $e1, $c4, $09, $03, $3a, $b4, $e8, $00, $19, $32, $d2, $c5, $31, $2a + byte $f1, $85, $84, $04, $00, $0d, $32, $44, $b0, $c0, $a8, $ce, $86, $e0, $15, $13 + byte $22, $00, $36, $28, $c1, $03, $c4, $e4, $0c, $df, $b0, $83, $07, $b4, $e0, $01 + byte $0e, $c4, $e2, $98, $0d, $18, $f0, $a7, $c4, $e8, $19, $3c, $41, $86, $4f, $8c + byte $18, $c0, $a3, $c5, $03, $1b, $66, $f2, $88, $1f, $e0, $82, $27, $a4, $e0, $01 + byte $0e, $2d, $18, $50, $38, $a1, $43, $0d, $3e, $98, $20, $a2, $0f, $5e, $20, $81 + byte $07, $6f, $cc, $e1, $11, $3c, $3a, $b0, $e1, $23, $78, $00, $0d, $5f, $c1, $13 + byte $02, $f8, $f0, $01, $1a, $14, $08, $e0, $40, $01, $03, $8c, $1f, $90, $a3, $03 + byte $84, $e8, $01, $26, $f8, $00, $80, $0b, $32, $78, $81, $8f, $0e, $c1, $13, $58 + byte $f8, $08, $1e, $30, $21, $c7, $0f, $08, $e0, $82, $27, $48, $10, $c0, $80, $00 + byte $0a, $1e, $30, $20, $41, $8c, $8f, $c9, $29, $78, $c3, $09, $be, $d1, $21, $3d + byte $84, $4f, $f8, $70, $a0, $87, $ef, $e4, $0a, $10, $3e, $6c, $68, $c1, $33, $3e + byte $65, $17, $78, $b0, $a1, $f8, $27, $44, $8f, $0e, $4d, $ee, $dc, $a8, $70, $a2 + byte $c8, $81, $3c, $5b, $32, $a4, $59, $f9, $27, $4c, $9f, $0f, $4d, $ea, $d4, $b8 + byte $50, $e2, $48, $81, $1d, $59, $36, $a4, $49, $f9, $27, $42, $9f, $0e, $af, $e0 + + byte $41, $85, $12, $c5, $e0, $49, $86, $75, $f0, $20, $4a, $80, $0e, $2d, $1a, $d1 + byte $8b, $02, $b9, $e8, $4d, $9c, $00, $dd, $e0, $41, $2d, $7c, $91, $23, $1b, $3f + byte $c2, $87, $7f, $82, $c1, $9b, $72, $f4, $08, $be, $88, $e8, $d1, $a6, $11, $3e + byte $82, $7f, $0a, $c0, $87, $9b, $26, $36, $2a, $c1, $df, $3f, $36, $fa, $78, $68 + byte $62, $a7, $8a, $99, $22, $06, $72, $68, $c9, $a0, $8e, $9f, $fe, $11, $e2, $c1 + byte $49, $1d, $2b, $65, $8c, $14, $d0, $91, $45, $43, $1a, $a5, $ff, $00, $80, $09 + byte $2f, $2e, $ec, $58, $31, $63, $0a, $fe, $d8, $d0, $e1, $c6, $41, $0d, $13, $26 + byte $0c, $e4, $d1, $a2, $41, $4d, $32, $7c, $fa, $c7, $80, $06, $05, $36, $2c, $c1 + byte $03, $7d, $f0, $8c, $5e, $fe, $21, $a1, $45, $89, $2c, $f8, $a2, $0a, $5f, $fe + byte $c1, $a1, $42, $8e, $14, $33, $46, $f4, $e8, $a2, $47, $f0, $81, $08, $1a, $05 + byte $50, $c4, $00, $83, $37, $49, $16, $c4, $b9, $51, $e3, $ca, $85, $33, $a5, $01 + byte $c4, $be, $26, $b0, $24, $41, $9c, $18, $51, $aa, $e5, $a1, $7b, $34, $00, $f2 + byte $e4, $82, $47, $f8, $64, $46, $94, $09, $11, $c2, $e1, $91, $42, $f0, $20, $4b + byte $96, $64, $f8, $0a, $0e, $84, $09, $11, $0c, $0e, $c1, $3f, $78, $10, $0a, $1e + byte $04, $e8, $07, $4f, $32, $e1, $37, $78, $d3, $a3, $47, $37, $f8, $13, $24, $18 + byte $3e, $82, $03, $5d, $3c, $e1, $17, $51, $70, $40, $40, $1f, $1f, $5d, $bc, $74 + + byte $48, $20, $27, $86, $94, $28, $92, $e4, $80, $90, $00, $fe, $e0, $89, $07, $4f + byte $7a, $40, $16, $1c, $88, $20, $0e, $9f, $c1, $9b, $0e, $0a, $e2, $c1, $93, $30 + byte $61, $44, $08, $11, $e0, $c7, $17, $3d, $f0, $e0, $46, $81, $1c, $19, $52, $24 + byte $e1, $21, $7c, $c4, $47, $bc, $78, $83, $57, $fc, $08, $9e, $08, $c3, $57, $f0 + byte $09, $df, $c1, $21, $7a, $86, $87, $e8, $1f, $7c, $71, $c7, $bf, $e8, $98, $3c + byte $e2, $23, $6c, $36, $2f, $93, $54, $2f, $c8, $0d, $bd, $91, $68, $eb, $24, $f3 + byte $30, $49, $55, $82, $4e, $39, $18, $88, $04, $2f, $d2, $a4, $83, $43, $2d, $0c + byte $cf, $a5, $83, $50, $78, $0b, $5e, $b5, $a1, $74, $44, $f7, $ca, $10, $1d, $10 + byte $37, $8e, $e0, $49, $12, $65, $2b, $a8, $95, $8d, $21, $7c, $20, $22, $44, $fb + byte $25, $04, $5f, $a4, $f1, $a2, $31, $d2, $c6, $45, $0b, $27, $89, $56, $58, $2b + byte $6b, $43, $67, $0c, $5e, $34, $70, $b4, $82, $5a, $41, $a4, $35, $21, $c4, $8d + byte $0b, $27, $4e, $1c, $d4, $b1, $63, $a3, $da, $29, $c3, $43, $6b, $c0, $1d, $1d + byte $82, $47, $70, $c0, $86, $15, $0b, $16, $cc, $c1, $0b, $57, $f8, $c0, $81, $23 + byte $f8, $62, $c2, $d4, $18, $82, $17, $f6, $e0, $81, $35, $7c, $60, $c6, $8c, $09 + byte $22, $46, $08, $f1, $29, $78, $43, $c1, $0c, $19, $13, $c6, $e0, $85, $03, $46 + byte $78, $80, $16, $9f, $20, $85, $0f, $0c, $e1, $03, $66, $7c, $0c, $0e, $50, $a1 + + byte $40, $0e, $0f, $10, $21, $62, $00, $7f, $85, $ce, $04, $fd, $b3, $44, $27, $6f + byte $64, $83, $c7, $71, $24, $d6, $e2, $59, $c2, $5d, $36, $8a, $c6, $16, $b8, $12 + byte $47, $82, $1e, $de, $3b, $11, $9e, $69, $86, $0f, $04, $e1, $65, $2d, $44, $87 + byte $a2, $59, $21, $ee, $10, $be, $a5, $10, $1e, $ea, $72, $bc, $c4, $bf, $26, $de + byte $c0, $93, $08, $4f, $75, $a1, $42, $84, $0f, $7a, $e1, $61, $2b, $46, $67, $1c + byte $7b, $38, $3a, $c6, $27, $9c, $45, $03, $7a, $b2, $88, $8e, $77, $28, $bc, $04 + byte $af, $cf, $71, $07, $61, $e3, $86, $15, $1e, $eb, $c2, $63, $c0, $0f, $0f, $2f + byte $dc, $64, $15, $bc, $a0, $63, $47, $00, $3f, $3c, $86, $0f, $d8, $b0, $61, $e1 + byte $8a, $17, $30, $a0, $43, $c3, $10, $1e, $f0, $c1, $85, $83, $07, $36, $2e, $58 + byte $30, $61, $06, $07, $ec, $d0, $d0, $83, $47, $07, $36, $3a, $c0, $8d, $17, $e1 + byte $25, $78, $80, $0b, $1e, $60, $d1, $80, $8e, $0e, $e1, $29, $3a, $40, $03, $0f + byte $0e, $1c, $5a, $30, $60, $40, $83, $02, $05, $12, $46, $74, $08, $1e, $50, $f7 + byte $06, $76, $ea, $eb, $60, $3c, $2d, $0b, $8c, $18, $92, $05, $0e, $1a, $eb, $68 + byte $59, $cf, $8b, $f1, $80, $7e, $6b, $6c, $f3, $69, $81, $01, $3d, $b8, $e0, $b5 + byte $8d, $21, $85, $a7, $6c, $70, $74, $b6, $c1, $3e, $5c, $96, $e1, $63, $6f, $42 + byte $4d, $96, $eb, $20, $7c, $40, $88, $0f, $f9, $20, $5e, $41, $c5, $02, $19, $73 + + byte $70, $80, $08, $01, $7c, $78, $00, $5b, $21, $b0, $05, $87, $e8, $00, $29, $bc + byte $80, $0b, $9e, $58, $c3, $e3, $d1, $0a, $0f, $65, $03, $2c, $58, $68, $e1, $01 + byte $4a, $78, $3a, $1b, $c1, $a3, $2a, $80, $05, $03, $2d, $59, $5c, $c5, $e8, $10 + byte $2f, $82, $4f, $78, $4c, $16, $90, $21, $85, $a7, $e8, $d8, $24, $a0, $3e, $89 + byte $f0, $11, $de, $db, $40, $f0, $7c, $13, $e1, $2d, $3e, $80, $0e, $ef, $7d, $30 + byte $38, $06, $cf, $f0, $9e, $0d, $06, $e7, $3a, $c0, $0b, $67, $6b, $1e, $c9, $32 + byte $11, $35, $d2, $c0, $b4, $08, $1e, $f3, $68, $2d, $e6, $85, $34, $19, $3c, $d0 + byte $80, $41, $bd, $b6, $83, $63, $f0, $04, $3b, $2f, $40, $83, $46, $05, $12, $04 + byte $f4, $b9, $19, $1c, $21, $a6, $8c, $75, $b0, $0c, $41, $00, $07, $16, $9d, $83 + byte $67, $78, $58, $1b, $20, $82, $27, $50, $20, $80, $2b, $67, $ce, $0c, $cf, $e1 + byte $23, $78, $02, $02, $08, $60, $6f, $81, $8c, $0f, $c1, $31, $f8, $46, $f7, $e8 + byte $00, $28, $7c, $9d, $85, $f0, $0c, $2c, $bc, $c0, $0f, $ef, $e1, $01, $70, $78 + byte $0c, $1e, $d9, $24, $bc, $c1, $8b, $8e, $d9, $24, $3e, $a6, $0b, $f8, $f0, $b2 + byte $79, $b4, $86, $07, $b7, $68, $64, $63, $20, $e1, $35, $78, $96, $85, $a2, $17 + byte $2d, $e0, $c2, $39, $95, $87, $60, $70, $44, $82, $14, $01, $18, $00, $3c, $58 + byte $fe, $83, $77, $2a, $8c, $18, $40, $00, $01, $80, $0b, $33, $78, $4f, $c6, $58 + + byte $50, $3c, $00, $c1, $87, $03, $c3, $ff, $a1, $6c, $89, $29, $13, $28, $60, $80 + byte $c1, $03, $7a, $f0, $e9, $81, $f1, $11, $20, $3c, $d8, $50, $83, $57, $74, $04 + byte $19, $5f, $92, $83, $ff, $4b, $94, $1c, $e2, $63, $74, $8a, $0f, $fe, $73, $26 + byte $98, $e8, $1e, $1f, $82, $47, $41, $80, $0d, $2b, $ba, $e4, $0b, $28, $fe, $fd + byte $d7, $88, $e3, $00, $73, $1f, $40, $ad, $0f, $f0, $f3, $65, $f0, $0a, $0f, $c1 + byte $63, $6d, $40, $86, $08, $0e, $76, $74, $f4, $1f, $9d, $ce, $26, $14, $48, $10 + byte $c0, $82, $02, $12, $1e, $82, $e7, $39, $80, $11, $9e, $c0, $83, $01, $11, $1c + byte $fd, $c7, $8b, $e0, $71, $16, $c2, $23, $38, $d0, $c0, $82, $4f, $b2, $3a, $02 + byte $e0, $c1, $82, $0c, $4e, $fe, $93, $65, $78, $4c, $96, $a0, $81, $07, $ef, $40 + byte $12, $0e, $90, $01, $41, $08, $00, $dd, $97, $00, $15, $7c, $c0, $83, $02, $8e + byte $04, $10, $02, $78, $78, $bf, $44, $24, $4d, $07, $dd, $03, $00, $7c, $bc, $f1 + byte $22, $f8, $82, $07, $09, $ac, $05, $16, $03, $5c, $89, $0c, $0c, $f0, $e9, $09 + byte $0f, $4e, $8f, $0c, $31, $10, $40, $02, $9d, $1f, $c1, $03, $76, $26, $8f, $00 + byte $31, $28, $f8, $87, $8e, $08, $d8, $11, $82, $7f, $f0, $00, $0b, $fc, $00, $c2 + byte $29, $e5, $41, $00, $54, $82, $88, $00, $c1, $3f, $08, $82, $88, $00, $70, $83 + byte $7f, $10, $02, $76, $12, $82, $7f, $10, $02, $03, $04, $40, $f0, $0f, $c2, $20 + + byte $01, $05, $ff, $20, $d2, $cb, $43, $1f, $0a, $e0, $c8, $80, $22, $01, $8c, $08 + byte $20, $02, $f8, $f8, $f6, $02, $1e, $d8, $b8, $50, $06, $2f, $c4, $80, $86, $01 + byte $fe, $7e, $81, $17, $0e, $ee, $b3, $80, $1c, $18, $52, $20, $e1, $3b, $3c, $04 + byte $af, $65, $f1, $25, $80, $84, $0f, $80, $c3, $00, $5f, $bf, $d8, $46, $38, $f6 + byte $41, $f8, $8b, $0f, $57, $0b, $3a, $54, $28, $90, $01, $85, $cf, $27, $05, $eb + byte $1c, $06, $2f, $48, $10, $a3, $47, $f0, $81, $75, $8f, $8e, $03, $44, $08, $e0 + byte $83, $37, $cc, $6b, $1d, $bc, $c1, $81, $4d, $4e, $b0, $61, $9e, $07, $a8, $c1 + byte $17, $0c, $e8, $70, $11, $3c, $de, $55, $fc, $88, $1e, $e1, $23, $78, $80, $02 + byte $b9, $21, $12, $40, $06, $08, $fe, $20, $e1, $c6, $c0, $1c, $98, $3c, $c3, $0f + byte $fc, $08, $08, $ad, $00, $04, $7f, $80, $11, $20, $01, $c7, $1f, $90, $bb, $20 + byte $02, $64, $88, $04, $04, $3e, $7a, $26, $07, $10, $b8, $5a, $00, $74, $ec, $d0 + byte $b0, $42, $c5, $82, $39, $17, $60, $8c, $95, $30, $71, $c2, $c0, $5e, $20, $b0 + byte $42, $81, $82, $19, $52, $26, $c0, $10, $2b, $70, $c2, $c4, $01, $1d, $5b, $47 + byte $48, $11, $25, $33, $3c, $82, $8f, $0e, $0d, $10, $6a, $8e, $0c, $3e, $e0, $e2 + byte $63, $0d, $8c, $0e, $c1, $a1, $64, $66, $c2, $e0, $1f, $1c, $a2, $53, $f8, $82 + byte $16, $5f, $21, $84, $c7, $e0, $1d, $9f, $d2, $65, $f0, $02, $0b, $23, $39, $c5 + + byte $27, $88, $d1, $39, $78, $40, $4f, $4e, $90, $07, $54, $74, $02, $0b, $22, $38 + byte $c4, $a7, $e8, $04, $be, $26, $06, $0f, $e0, $c0, $e2, $73, $74, $02, $d7, $10 + byte $41, $04, $0f, $a0, $40, $80, $44, $57, $b0, $60, $c1, $04, $6f, $c0, $80, $01 + byte $25, $1b, $30, $c1, $f7, $78, $9c, $c0, $e8, $04, $3a, $3a, $dc, $cf, $f0, $10 + byte $1c, $4e, $f0, $8a, $40, $9f, $30, $62, $01, $68, $d0, $43, $02, $24, $88, $b8 + byte $50, $25, $23, $d1, $e6, $0c, $5e, $c0, $d3, $22, $d0, $f0, $3a, $25, $d3, $64 + byte $5c, $8c, $ee, $c1, $21, $3c, $01, $29, $88, $d1, $39, $5e, $02, $0b, $8f, $40 + byte $0a, $62, $b2, $89, $d7, $40, $00, $a7, $83, $f0, $1e, $9e, $82, $67, $78, $07 + byte $5a, $07, $aa, $40, $85, $c8, $1b, $e9, $3c, $3a, $00, $8a, $16, $45, $3b, $de + byte $56, $81, $78, $1f, $af, $1b, $47, $f0, $7c, $04, $79, $37, $5c, $04, $8f, $64 + byte $95, $77, $7b, $25, $40, $80, $f1, $7e, $14, $84, $27, $00, $c1, $33, $3c, $01 + byte $cf, $5a, $d1, $02, $00, $80, $36, $16, $9e, $a2, $c5, $20, $b8, $f3, $7d, $08 + byte $6c, $b4, $f8, $e2, $5d, $18, $14, $a8, $92, $f8, $46, $ba, $60, $d6, $ca, $c4 + byte $00, $8e, $72, $59, $ce, $c4, $4b, $13, $de, $a2, $01, $b1, $16, $b7, $22, $7c + byte $78, $70, $e1, $c0, $81, $1d, $2f, $56, $01, $a0, $5c, $14, $1c, $83, $07, $6c + byte $d8, $b0, $60, $7e, $8b, $23, $1d, $5e, $82, $43, $f0, $80, $1e, $de, $c3, $45 + + byte $78, $fc, $07, $25, $0b, $5e, $bc, $8c, $36, $ff, $20, $99, $47, $6b, $68, $50 + byte $1b, $44, $32, $81, $15, $ad, $83, $67, $70, $c8, $da, $69, $2b, $5a, $40, $85 + byte $02, $3f, $ed, $c3, $08, $4e, $c1, $23, $5c, $e4, $c5, $68, $fd, $2e, $db, $45 + byte $da, $cf, $0a, $f1, $20, $38, $40, $5a, $46, $6b, $61, $5c, $16, $c1, $b8, $54 + byte $23, $f6, $52, $af, $cc, $83, $85, $69, $1e, $85, $8b, $e0, $0f, $7b, $2f, $7c + byte $a6, $4e, $d9, $33, $d3, $50, $f0, $0c, $0f, $40, $83, $5f, $a1, $00, $1e, $de + byte $e3, $15, $2c, $18, $c1, $23, $6d, $a5, $e3, $11, $50, $09, $73, $41, $c5, $88 + byte $f7, $fd, $b3, $10, $43, $84, $00, $3e, $5a, $c3, $ac, $49, $90, $21, $ef, $40 + byte $f0, $db, $e1, $68, $84, $87, $68, $15, $5c, $b7, $45, $59, $cc, $02, $35, $31 + byte $5a, $1e, $23, $50, $79, $21, $2d, $00, $0a, $97, $c1, $73, $1f, $be, $81, $ac + byte $00, $04, $10, $80, $78, $1e, $2d, $5a, $03, $60, $80, $f0, $92, $0e, $98, $70 + byte $01, $22, $38, $c1, $87, $13, $4f, $93, $36, $c0, $e0, $00, $1d, $76, $c1, $84 + byte $1a, $0b, $20, $80, $05, $e5, $3f, $00, $57, $84, $82, $91, $31, $20, $82, $03 + byte $0d, $3c, $f8, $84, $17, $f0, $60, $41, $06, $17, $ff, $15, $11, $0a, $24, $08 + byte $e1, $dd, $3f, $8c, $8a, $00, $19, $62, $78, $8f, $04, $f1, $32, $3c, $01, $8d + byte $ae, $fe, $c3, $33, $18, $10, $c1, $cd, $7f, $bf, $08, $0f, $59, $2f, $14, $25 + + byte $63, $60, $e1, $dd, $7f, $32, $8c, $f6, $a1, $0a, $10, $7c, $b8, $30, $c3, $7d + byte $10, $04, $00, $17, $56, $70, $0f, $42, $f0, $60, $43, $0d, $fe, $41, $08, $36 + byte $b4, $e0, $1e, $84, $a1, $07, $f7, $20, $1e, $c4, $83, $30, $94, $04, $d1, $30 + byte $0a, $45, $c3, $58, $99, $93, $32, $64, $40, $ce, $10, $d0, $47, $c4, $e4, $08 + byte $7e, $25, $01, $0c, $4c, $68, $95, $69, $13, $84, $ef, $58, $09, $3a, $02, $ac + byte $8e, $5e, $70, $92, $92, $c9, $b4, $80, $92, $00, $83, $7f, $28, $00, $0d, $0c + byte $f0, $24, $08, $fe, $91, $08, $68, $93, $00, $fb, $12, $86, $78, $48, $00, $7a + byte $0e, $e0, $3c, $8c, $b6, $df, $b6, $8f, $45, $39, $0f, $c2, $70, $fa, $7e, $63 + byte $0f, $e2, $41, $3c, $88, $07, $f1, $20, $1e, $c4, $83, $78, $10, $0f, $a2, $c0 + byte $81, $01, $05, $02, $04, $30, $20, $80, $00, $e0, $c3, $83, $07, $17, $0e, $6c + byte $d8, $c1, $2b, $38, $04, $6f, $b8, $c1, $13, $56, $f0, $09, $0f, $e1, $33, $3c + byte $05, $ff, $e8, $10, $9e, $61, $86, $bf, $e0, $19, $2f, $61, $05, $af, $64, $1d + byte $bc, $83, $03, $8c, $f0, $91, $6e, $93, $51, $f0, $4f, $36, $c1, $11, $7a, $f8 + byte $0e, $ee, $30, $a0, $43, $df, $0a, $80, $8b, $51, $74, $82, $19, $1c, $a0, $9d + byte $6d, $00, $65, $29, $5a, $41, $fb, $86, $57, $07, $76, $70, $81, $d2, $98, $b6 + byte $c4, $59, $8e, $0b, $50, $a1, $40, $6e, $ad, $57, $b2, $0d, $16, $09, $88, $dd + + byte $3f, $08, $b4, $82, $34, $d8, $ff, $83, $28, $2c, $90, $20, $40, $34, $cc, $41 + byte $d0, $4b, $e0, $c3, $cc, $85, $c0, $e2, $52, $a3, $2a, $9d, $c1, $31, $75, $35 + byte $a2, $89, $5d, $b2, $a0, $66, $4e, $48, $90, $20, $ce, $e4, $8a, $58, $0a, $72 + byte $03, $e4, $e0, $00, $01, $3c, $78, $70, $60, $e1, $04, $cf, $70, $11, $3c, $82 + byte $63, $f0, $08, $0e, $60, $40, $c7, $c3, $68, $05, $11, $42, $70, $01, $0d, $2d + byte $5a, $85, $8b, $e0, $11, $0d, $c3, $05, $68, $50, $c1, $3d, $1a, $05, $07, $90 + byte $d1, $38, $dc, $36, $82, $72, $90, $94, $82, $7b, $95, $cc, $c2, $e0, $a2, $51 + byte $47, $ac, $83, $b9, $2b, $d8, $37, $ca, $cc, $12, $76, $6a, $d1, $9c, $4c, $95 + byte $1d, $09, $c8, $2b, $82, $0b, $a3, $86, $a6, $0c, $f8, $1b, $01, $16, $0c, $a8 + byte $e1, $f3, $76, $2c, $cd, $da, $9d, $0e, $5f, $4d, $a7, $6e, $d4, $b7, $75, $6d + byte $67, $ad, $68, $b8, $67, $21, $47, $cb, $46, $00, $fb, $88, $05, $17, $b0, $d9 + byte $30, $a9, $15, $e5, $22, $57, $79, $cb, $f8, $c7, $8e, $9b, $65, $7a, $6b, $15 + byte $47, $d8, $b9, $01, $5a, $4b, $ac, $4d, $f0, $4b, $67, $e6, $80, $0e, $15, $f2 + byte $19, $8a, $5a, $b9, $23, $1c, $fe, $05, $70, $e1, $70, $77, $c2, $8d, $13, $30 + byte $a0, $05, $cb, $57, $14, $15, $83, $35, $44, $b0, $2f, $29, $58, $45, $49, $c8 + byte $e0, $df, $2f, $9c, $8e, $01, $0d, $f2, $2f, $0f, $e2, $41, $7c, $fa, $6c, $0e + + byte $e0, $40, $01, $03, $84, $7f, $2f, $fc, $9f, $66, $50, $a5, $22, $38, $43, $8f + byte $0c, $6b, $3b, $b8, $42, $8b, $95, $60, $6f, $41, $b8, $85, $9d, $b0, $83, $43 + byte $dc, $81, $17, $5c, $fc, $83, $0e, $0e, $c0, $e2, $06, $00, $b8, $30, $33, $2c + byte $c8, $16, $b0, $07, $00, $c0, $c9, $fe, $d0, $81, $42, $86, $08, $0e, $54, $e1 + byte $f7, $0f, $15, $12, $04, $30, $a5, $3e, $08, $86, $83, $6a, $1e, $c4, $83, $78 + byte $10, $0f, $e2, $41, $3c, $88, $07, $f1, $20, $1e, $c4, $83, $78, $10, $0f, $02 + +DAT +{{ + + TERMS OF USE: MIT License + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + associated documentation files (the "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +}} +DAT diff --git a/source/boing/boing-bel-foreground.spin b/source/boing/boing-bel-foreground.spin new file mode 100644 index 0000000..f561831 --- /dev/null +++ b/source/boing/boing-bel-foreground.spin @@ -0,0 +1,505 @@ +'' +'' VGA scanline driver 400x300 - foreground renderer +'' +'' Based on "Ball" demo for Gameduino +'' Copyright (c) 2011 by James Bowman +'' +'' Author: Marko Lukat +'' Last modified: 2012/12/24 +'' Version: 0.11 +'' +OBJ + system: "boing-bel-corecon" + +PUB null +'' This is not a top level object. + +PUB init(ID, mailbox) + + return system.launch(ID, @entry, mailbox) + +DAT org 0 ' foreground renderer + +entry jmpret $, #setup ' once + + rdlong indx, blnk ' | + cmpsub indx, scry wz ' | + if_ne jmp #$-2 ' waiting for last line to be fetched + +' Skip 26 sync lines and advance by a further 161 hub windows. This pushes an +' assumed foreground renderer hubop beyond the first video renderer line rdlong +' if it were to render scanline -1. +' After the waitcnt we have no further insns (18 + 14 = 32, 2 hub windows). + + mov cnt, cnt + add cnt, $+1 + long 13{18} + 14 + 132*16*26 + 16*(161 - 2) + +loop waitcnt cnt, eins ' initial sync point +' wrbyte indx, base ' assumed hubop + + call #pixels ' fetch foreground data (~92 hub windows) + + waitcnt cnt, zwei ' block until line is available + + rdlong bflag, bfadr wz + if_nz call #shadow ' draw shadow + cmp bflag, #0 wz + if_nz call #solid ' draw ball + + rol mask, #8 ' update shadow mask, it's unused + ' during 1st frame (msky == scry) + add indx, #1 ' line done, advance + cmpsub indx, scry wz ' optionally wrap line index + if_nz jmp #loop + +' per frame updates (during the first frame mask/shadow are off-screen) + + rdlong temp, blnk ' | + cmp temp, scry wz ' | + if_ne jmp #$-2 ' wait for ?/scry transition + + rdword mskx, crdx ' | + shl mskx, #16 ' | + sar mskx, #16 ' | + rdword msky, crdy ' | + shl msky, #16 ' | + sar msky, #16 ' update and sign-extend mask coordinates + + maxs mskx, scrx ' | + maxs msky, scry ' reasonable limit(s) (off-screen) + + mov shdx, mskx ' | + add shdx, #SOFFX ' | + mov shdy, msky ' | + add shdy, #SOFFY ' apply shadow offset(s) + + mov mskc, msky ' | + add mskc, #BSIZE -1 ' | + mov shdc, shdy ' | + add shdc, #BSIZE -1 ' bounding box setup + + long $00FF00FF ' | + mov mask, $-1 ' reset shadow mask (scry == 2n+?) + +eins long 100*16 ' initial line fetch +zwei long 164*16 ' remainder of two scan lines +drei long 132*16*28 ' skip all sync lines + + add cnt, drei + jmp #loop + +' support code + +pixels rdlong addr, feed wz ' get current buffer address + + if_z mov msky, scry ' move off-screen (disabled) + if_z jmp pixels_ret ' early exit + + mov ecnt, #BSIZE/4 + movd :set, #data + + mov temp, mskx ' | + and temp, #%11 wz ' observe alignment + + shl temp, #3 ' [4..0]: 24/16/8/0 + movs :two, temp + neg temp, temp ' [4..0]: 8/16/24/0 + movs :one, temp + + if_nz add ecnt, #1 ' need to process one more long + if_nz sub addr, #4 ' starting with addr[-1] + +:loop rdlong arg0, addr ' +0 = 00: DDCCBBAA, 01: ------DD + add addr, #4 ' +8 10: ----DDCC, 11: --DDCCBB + if_z jmp #:set ' -4 faster if aligned + + rdlong arg1, addr ' +0 = 00: n/a, 01: CCBBAA-- +:two shl arg1, #0-0 ' +8 10: BBAA----, 11: AA------ +:one shr arg0, #0-0 ' -4 + or arg0, arg1 ' +0 = + +:set mov 0-0, arg0 ' +4 + add $-1, dst1 ' +8 + + djnz ecnt, #:loop ' -4 + +pixels_ret ret + +solid cmps indx, msky wc ' | + if_nc cmps mskc, indx wc ' | + if_c jmp solid_ret ' vertical bounds check + + mov temp, indx + sub temp, msky + cmp temp, #BSIZE/2 wc + if_nc neg temp, temp + if_nc add temp, #BSIZE-1 + add temp, #table ' offset into table + + movs $+2, temp + neg arg2, #1 ' pipeline + mov arg0, 0-0 ' fetch offset/length pair + + mov arg1, arg0 + shr arg1, #16 wz ' length + + and arg0, #511 ' relative offset + add arg0, mskx ' absolute offset + + add arg2, arg0 ' | + add arg2, arg1 ' right side inclusive + + cmps arg2, #0 wc + if_nc cmps scrc, arg0 wc ' | + if_z_or_c jmp solid_ret ' horizontal bounds check + + cmps arg0, #0 wc ' | + if_c subabs arg1, arg0 ' | + if_c mov arg0, #0 ' clipped left + + cmps scrc, arg2 wc ' | + if_c mov arg1, scrx ' | + if_c sub arg1, arg0 ' clipped right side + +' arg0..(arg0+arg1-1) fits into the scanline buffer, draw the line + + mov addr, base + add addr, arg0 ' @byte[base][arg0] + + mov arg2, mskx ' | + and arg2, #%11 ' | + add arg2, arg0 ' | + sub arg2, mskx ' byte offset into data array + + shr arg1, #2 wz,nr ' special code for 1..3 + if_nz jmpret zero, #:full wc,nr ' carry set if taken (##) + + ' do an unaligned load + + mov arg0, arg2 ' remember for byte alignment + + shr arg2, #2 ' long offset + add arg2, #data ' long address + + movs $+2, arg2 + add arg2, #1 ' pipeline + mov arg3, 0-0 ' load 1st long + movs $+2, arg2 + test arg0, #%11 wz ' pipeline + mov arg2, 0-0 ' load 2nd long + + if_nz shl arg0, #3 ' 00: DDCCBBAA, 01: --DDCCBB + if_nz shr arg3, arg0 ' 10: ----DDCC, 11: ------DD + if_nz neg arg0, arg0 ' 00: n/a, 01: AA------ + if_nz shl arg2, arg0 ' 10: BBAA----, 11: CCBBAA-- + if_nz or arg3, arg2 ' combine both longs + + wrbyte arg3, addr + add addr, #1 + shr arg3, #8 + djnz arg1, #$-3 ' relaxed @ 2 hub windows/byte + + jmp solid_ret + +' length is prefix + 4n + suffix, split up and deal with it + +:full shr arg2, #2 ' long offset + add arg2, #data ' long address + + neg ecnt, arg0 ' 0123 >> 0321 + and ecnt, #%11 wz ' pixels in prefix + sub arg1, ecnt ' update length + if_z jmp #:core + + ' handle prefix + + shl arg0, #3 ' 1..3 >> 8..24 + rcr ecnt, arg0 ' create reverse mask (##) + + movs $+2, arg2 ' prefix data + rev ecnt, #0 ' adjust + + mov arg3, 0-0 ' | + andn arg3, ecnt ' only keep masked data + + rdlong quad, addr + and quad, ecnt + or quad, arg3 ' combine with background + wrlong quad, addr + + add arg2, #1 ' advance src + add addr, #4 ' advance dst + andn addr, #%11 ' | + + ' handle 4 + +:core test arg1, #%100 wz + if_nz movd $+2, arg2 + if_nz sub arg1, #4 ' update length + if_nz wrlong 0-0, addr + if_nz add addr, #4 ' advance dst + if_nz add arg2, #1 ' advance src + + ' handle 8n + + mov ecnt, arg1 ' remember for tail (%-??) + shr arg1, #3 wz ' check 8n count + if_z jmp #:suffix ' skip body + + mov frqb, addr + shr frqb, #1{/2} + + add arg2, arg1 ' | + add arg2, arg1 ' advance src + + movd :one, arg2 + sub :one, dst1 ' data[n][-1] + movd :two, arg2 + sub :two, dst2 ' data[n][-2] + + mov phsb, arg1 + shl phsb, #3 + mov addr, phsb ' advance dst + sub phsb, #1 ' 8n - 1 + +:one wrlong 0-0, phsb + sub $-1, dst2 + sub phsb, #7 wz +:two wrlong 0-0, phsb + sub $-1, dst2 + if_nz djnz phsb, #:one + + ' handle suffix + +:suffix and ecnt, #%11 wz ' suffix (unaligned) + if_z jmp solid_ret ' early exit + + shl ecnt, #3 ' 1..3 >> 8..24 + neg arg1, #1 ' create mask + + movs $+2, arg2 ' suffix data + shl arg1, ecnt ' adjust + + mov arg3, 0-0 ' | + andn arg3, arg1 ' only keep masked data + + rdlong quad, addr + and quad, arg1 + or quad, arg3 ' combine with background + wrlong quad, addr + +solid_ret ret + +shadow cmps indx, shdy wc ' | + if_nc cmps shdc, indx wc ' | + if_c jmp shadow_ret ' vertical bounds check + + mov temp, indx + sub temp, shdy + cmp temp, #BSIZE/2 wc + if_nc neg temp, temp + if_nc add temp, #BSIZE-1 + add temp, #table ' offset into table + + movs $+2, temp + neg arg2, #1 ' pipeline + mov arg0, 0-0 ' fetch offset/length pair + + mov arg1, arg0 + shr arg1, #16 wz ' length + + and arg0, #511 ' relative offset + add arg0, shdx ' absolute offset + + add arg2, arg0 ' | + add arg2, arg1 ' right side inclusive + + cmps arg2, #0 wc + if_nc cmps scrc, arg0 wc ' | + if_z_or_c jmp shadow_ret ' horizontal bounds check + + cmps arg0, #0 wc ' | + if_c subabs arg1, arg0 ' | + if_c mov arg0, #0 ' clipped left + + cmps scrc, arg2 wc ' | + if_c mov arg1, scrx ' | + if_c sub arg1, arg0 ' clipped right side + +' arg0..(arg0+arg1-1) fits into the scanline buffer, draw the line + + mov addr, base + add addr, arg0 ' @byte[base][arg0] + + shr arg1, #2 wz,wc,nr ' special code for 1..3 + if_nz jmpret zero, #:full wc,nr ' carry set if taken (##) + + test arg0, #1 wz + if_nz rol mask, #8 ' odd bytes only + + rdbyte quad, addr + and quad, mask + rol mask, #8 + wrbyte quad, addr + add addr, #1 + djnz arg1, #$-5 + + if_c_eq_z rol mask, #8 ' restore mask + + jmp shadow_ret + +:full neg ecnt, arg0 ' 0123 >> 0321 + and ecnt, #%11 wz ' pixels in prefix + sub arg1, ecnt ' update length + if_z jmp #:core + + shl arg0, #3 ' 1..3 >> 8..24 + rcr ecnt, arg0 ' create reverse mask (##) + rev ecnt, #0 ' adjust + + rdlong quad, addr + or ecnt, mask ' add shadow mask + and quad, ecnt + wrlong quad, addr + + add addr, #4 +'{rd/wrlong} andn addr, #%11 + +:core mov ecnt, arg1 ' remember for tail (%-??) + shr arg1, #2 wz ' check long count + if_z jmp #:tail ' skip body + + rdlong quad, addr + and quad, mask + cmp arg1, #1 wz + wrlong quad, addr + add addr, #4 + if_nz djnz arg1, #$-5 + +:tail and ecnt, #%11 wz ' suffix (unaligned) + if_z jmp shadow_ret ' early exit + + shl ecnt, #3 ' 1..3 >> 8..24 + neg arg1, #1 ' | + shl arg1, ecnt ' protect unused pixels + rdlong quad, addr + or arg1, mask ' add shadow mask + and quad, arg1 + wrlong quad, addr + +shadow_ret ret + +' initialised data and/or presets + +table word 48, 16, 43, 26, 39, 34, 36, 40, 34, 44, 32, 48, 30, 52, 28, 56 + word 26, 60, 25, 62, 23, 66, 22, 68, 21, 70, 19, 74, 18, 76, 17, 78 + word 16, 80, 15, 82, 14, 84, 13, 86, 13, 86, 12, 88, 11, 90, 10, 92 + word 10, 92, 9, 94, 8, 96, 8, 96, 7, 98, 7, 98, 6, 100, 6, 100 + word 5, 102, 5, 102, 4, 104, 4, 104, 3, 106, 3, 106, 3, 106, 2, 108 + word 2, 108, 2, 108, 2, 108, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110 + word 0, 112, 0, 112, 0, 112, 0, 112, 0, 112, 0, 112, 0, 112, 0, 112 + +feed long -12 ' | +crdx long -8 ' | +crdy long -6 ' | + ' quick access relative to par +blnk long -4 ' | +base long NEGX ' | + +dst1 long 1 << 9 ' dst +/-= 1 +dst2 long 2 << 9 ' dst +/-= 2 + +scrc long 399 ' upper limit (inclusive) +scrx long 400 + +bfadr long 448 +bflag long 0 + +' Stuff below is re-purposed for temporary storage. + +setup add crdx, par ' mask coordinates (%%) + add crdy, par ' | + add feed, par ' mask buffer location + + add base, par ' scanline buffer + add blnk, base wc ' frame indicator + + rdword indx, blnk wz ' (%%) + if_nz mov scry, indx wc ' (%%) + if_c_or_nz jmp #$-2 ' auto-detect res_y + +' The loop is only left once a non-zero value has been written to scry +' and indx transitions to zero afterwards. + + mov msky, scry ' move off-screen + mov shdy, scry ' | + + movi ctrb, #%0_11111_000 ' LOGIC always (loader support) + + add bfadr, par + jmp %%0 ' return + + fit + +' uninitialised data and/or temporaries + + org setup + +scry res 1 ' must be 1st..5th (%%) +indx res 1 ' | + +addr res 1 ' scanline reference +ecnt res 1 ' element count + +mask res 1 ' shadow mask + +mskc res 1 ' upper limit (inclusive) +mskx res 1 ' mask coordinates +msky res 1 ' signed 16bit + +shdc res 1 ' upper limit (inclusive) +shdx res 1 ' shadow coordinates +shdy res 1 ' signed 16bit + +arg0 res 1 +arg1 res 1 +arg2 res 1 +arg3 res 1 + +temp res 1 +quad res 1 + +data res BSIZE/4 +1{unaligned} + +tail fit + +CON + zero = $1F0 ' par (dst only) + + BSIZE = 112 ' mask width/height (4n) + SOFFX = 15 ' | + SOFFY = 15 ' shadow offset + +DAT +{{ + + TERMS OF USE: MIT License + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + associated documentation files (the "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +}} +DAT diff --git a/source/boing/boing-bel.spin b/source/boing/boing-bel.spin new file mode 100644 index 0000000..cdb4586 --- /dev/null +++ b/source/boing/boing-bel.spin @@ -0,0 +1,286 @@ +'' +'' VGA scanline driver 400x300 - demo +'' +'' Based on "Ball" demo for Gameduino +'' Copyright (c) 2011 by James Bowman +'' +'' Author: Marko Lukat +'' Last modified: 2012/12/24 +'' Version: 0.10 +'' +'' A few notes on timing. A (double) scan line lasts 2*(100+32) hub windows. +'' The background renderer fills the scan line as soon as the video driver +'' has read the relevant quad. At the same time the foreground renderer +'' fetches its data line. +'' +'' +-- video driver reads line N +'' +-- background renderer fills line N+1 +'' +-- foreground renderer fetches data for line N+1 +'' | +'' | +-- scanline N completely fetched +'' | +-- background renderer idle +'' | visible line area +-- foreground renderer draws shadow and ball +'' | | +'' ----------- 100 -----------#---32--- +'' ----------- 100 -----------+---32--- +'' ----------- 100 -----------#---32--- +'' | +'' +-- video driver reads line N+1 +'' +CON + _clkmode = XTAL1|PLL16X + _xinfreq = 5_000_000 + +CON + res_x = driver#res_x + res_y = driver#res_y + +OBJ + driver: "boing-bel-driver" + + back: "boing-bel-background" + ball: "boing-bel-foreground" + anim: "boing-bel-feeder" + + keyb: "bel-keyb" + gcon: "glob-con" + +VAR + long feeder ' @scan[-3] + long coordinates ' @scan[-2] + long frame ' @scan[-1] + long scan[res_x / 4] + long grid[12] + long bflag + +PUB main | cmd + + init +' boing + + repeat + case gc + 1: pc(keyb.gotkey) 'tastaturstatus senden + 2: pc(keyb.key) 'tastaturzeichen senden + 3: coordinates.word[0] := gw + coordinates.word[1] := gw + 4: waitVBL + 5: boing + 6: bars{gc,gc,gc} + 7: grid_on + 8: grid_off + 9: show_on + 10: bar_on + 11: bflag := gc + 12: grid[gc] := gw + 99: reboot + +PRI init + + dira := db_in ' datenbus auf eingabe schalten + outa[gcon#bus_hs] := 1 ' handshake inaktiv + keyb.start(gcon#b_keybd, gcon#b_keybc) ' tastaturport starten + driver.init(-1, @scan{0}) ' scanline driver + back.init(-1, @scan{0}) ' background + ball.init(-1, @scan{0}) ' foreground + anim.init(-1, @scan{0}) ' image feeder + grid_on + bflag := 0 + anim.uncompress(FALSE) ' uncompress image + + +CON ''------------------------------------------------- SUBPROTOKOLL-FUNKTIONEN + +' hbeat --------+ +' clk -------+| +' /wr ------+|| +' /hs -----+||| +------------------------- /cs +' |||| | -------- d0..d7 +DB_IN = %00001001_00000000_00000000_00000000 'maske: dbus-eingabe +DB_OUT = %00001001_00000000_00000000_11111111 'maske: dbus-ausgabe + +M1 = %00000010_00000000_00000000_00000000 +M2 = %00000010_10000000_00000000_00000000 'busclk=1? & /cs=0? + +M3 = %00000000_00000000_00000000_00000000 +M4 = %00000010_00000000_00000000_00000000 'busclk=0? + +PUB pc(zeichen) 'chip: ein byte an regnatix senden +''funktionsgruppe : chip +''funktion : ein byte an regnatix senden +''eingabe : byte +''ausgabe : - + + waitpeq(M1,M2,0) 'busclk=1? & prop2=0? + dira := db_out 'datenbus auf ausgabe stellen + outa[7..0] := zeichen 'daten ausgeben + outa[gcon#bus_hs] := 0 'daten gültig + waitpeq(M3,M4,0) 'busclk=0? + dira := db_in 'bus freigeben + outa[gcon#bus_hs] := 1 'daten ungültig + +PUB gc:zeichen 'chip: ein byte von regnatix empfangen +''funktionsgruppe : chip +''funktion : ein byte von regnatix empfangen +''eingabe : - +''ausgabe : byte + + waitpeq(M1,M2,0) 'busclk=1? & prop2=0? + zeichen := ina[7..0] 'daten einlesen + outa[gcon#bus_hs] := 0 'daten quittieren + waitpeq(M3,M4,0) 'busclk=0? + outa[gcon#bus_hs] := 1 + + +PUB pw(wert) 'sub: word senden +''funktionsgruppe : sub +''funktion : subprotokoll um einen long-wert an regnatix zu senden +''eingabe : 16bit wert der gesendet werden soll +''ausgabe : - +''busprotokoll : [put.byte1][put.byte2] +'' : [ hsb ][ ] + + pc(wert >> 8) + pc(wert) + +PUB gw:wert 'sub: word empfangen +''funktionsgruppe : sub +''funktion : subprotokoll um einen 16bit-wert von regnatix zu empfangen +''eingabe : - +''ausgabe : 16bit-wert der empfangen wurde +''busprotokoll : [get.byte1][get.byte2] +'' : [ hsb ][ lsb ] + + wert := gc << 8 + wert := wert + gc + +PUB gl:wert 'sub: long empfangen +''funktionsgruppe : sub +''funktion : subprotokoll um einen long-wert von regnatix zu empfangen +''eingabe : - +''ausgabe : 32bit-wert der empfangen wurde +''busprotokoll : [get.byte1][get.byte2][get.byte3][get.byte4] +'' : [ hsb ][ ][ ][ lsb ] + + wert := gc << 24 '32 bit empfangen hsb/lsb + wert := wert + gc << 16 + wert := wert + gc << 8 + wert := wert + gc + +CON ''------------------------------------------------- DEMO-FUNKTIONEN + LBASE = 0 + RBASE = res_x - ball#BSIZE + YBASE = res_y - ball#BSIZE + + MBAR = %00000000_11111111 + BLINE = 1 + +PRI boing : r | bx, by, bxv, byv + + bx := 0 + by := 0 + bxv := 2 + byv := 1 + + repeat + bx += bxv + by += byv + + if bx < LBASE + bx := constant(2*LBASE) - bx + -bxv + + if bx > RBASE + bx := constant(2*RBASE) - bx + -bxv + + if by > YBASE + by := constant(2*YBASE) - by + -byv + + ifnot ++r & 7 ' add some gravity + byv++ + + repeat 1 + waitVBL + coordinates.word{0} := bx ' | + coordinates.word[1] := by ' update coordinates + +PRI bars + + grid[BLINE ] := bar(gc) + grid[BLINE+2] := bar(gc) + grid[BLINE+4] := bar(gc) + +PRI bar(level):b + + b := MBAR + b := !(b >> (level & 7)) & MBAR + b := b | b >< 16 + +PRI grid_on|i + + repeat i from 0 to 11 + grid[i] := 0 + +PRI grid_off|i + + repeat i from 0 to 11 + grid[i] := $FFFF + +PRI show_on|i,n + + n := %00000000_11111111 + + repeat 19 + repeat i from 11 to 0 + grid[i] := grid[i-1] + n := n >> 1 + grid[0] := n | n >< 16 + waitcnt(cnt + clkfreq/30) + +PRI bar_on + + bar_up(BLINE ) + waitcnt(cnt + clkfreq/3) + bar_up(BLINE+2) + waitcnt(cnt + clkfreq/3) + bar_up(BLINE+4) + waitcnt(cnt + clkfreq/3) + +PRI bar_up(upline)|i + + repeat i from 11 to upline + grid[(i+1) <# 11] := 0 + grid[i] := %00000111_11100000 + waitcnt(cnt+clkfreq/20) + +PRI waitVBL + + repeat + until frame == res_y ' last line has been fetched + repeat + until frame <> res_y ' vertical blank starts (res_y/0 transition) + +DAT +{{ + + TERMS OF USE: MIT License + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + associated documentation files (the "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +}} +DAT diff --git a/source/boing/boing-reg.spin b/source/boing/boing-reg.spin new file mode 100644 index 0000000..f1fe188 --- /dev/null +++ b/source/boing/boing-reg.spin @@ -0,0 +1,272 @@ +{{ + +}} + +OBJ + ios: "reg-ios" + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + +SIDMASK = %00000000_00000000_00000000_00010000 + +VAR + + long dmpreg + long fcnt + long fpos + long datcnt 'zeiger für dateiliste + byte fl_bye 'flag player beenden + byte fn[12] 'puffer für dateinamen + long dmu 'marker des aktuellen userverzeichnisses + long bx,by,bxv,byv + +PUB main | key + + ios.start + + ios.belload(string("boing.bel")) + ios.sdclose + + ifnot (ios.admgetspec & SIDMASK) + ios.sddmset(ios#DM_USER) 'u-marker setzen + dmu := ios.sddmget(ios#DM_USER) 'usermarker von administra holen + ios.admload(string("boing.adm")) + ios.sddmput(ios#DM_USER,dmu) 'usermarker wieder in administra setzen + ios.sddmact(ios#DM_USER) 'u-marker aktivieren + + play_count + repeat + intro + \boing(string("boing.sid")) + play_dir + + ios.belreset + ios.admreset + waitcnt(cnt+clkfreq*2) + ios.stop + +PRI esc_key + + if ios.g0_keystat + case ios.g0_keycode + 27: + 'ESC - geordneter rücksturz zur erde... :) + ios.sid_dmpstop 'ok, erstmal die mucke aus + ios.sid_mute(3) + ios.belreset + ios.sddmset(ios#DM_USER) 'u-marker setzen + dmu := ios.sddmget(ios#DM_USER) 'usermarker von administra holen + ios.admreset + waitcnt(cnt+clkfreq*2) + ios.sddmput(ios#DM_USER,dmu) 'usermarker wieder in administra setzen + ios.sddmact(ios#DM_USER) 'u-marker aktivieren + credits + ios.stop + "n": + ios.sid_dmpstop + ios.sid_mute(3) + abort + "p": + ios.sid_dmppause + +PRI credits + + ios.curoff + ios.printcls + ios.printnl + ios.print(string("Bouncing Ball for Hive - 2013 ",$0d,$0d)) + ios.print(string("Graphics-Code : kuroneko",$0d)) + ios.print(string("SidCog : Ahle2 ",$0d)) + ios.print(string("Hive-Code : drohne235",$0d,$0d)) + + ios.curon + +CON 'sd-player +PRI play_dir|stradr,len,i 'alle songs auf der sd-card abspielen + + datcnt := 0 'zum listenanfang + repeat i from 0 to fcnt-1 'dateiliste abspielen + fpos := i + 1 + play_dir_rdlst(@fn) + \boing(@fn) + +PRI play_count|stradr,i + + ios.sddir 'kommando: verzeichnis öffnen + datcnt := 0 'zum listenanfang + fcnt := 0 'zähler für dateianzahl + fl_bye := 0 + repeat while (stradr := ios.sdnext) 'dateiliste einlesen + if str_find(stradr,string(".DMP")) + fcnt++ + play_dir_wrlst(stradr) + +PRI play_dir_wrlst(stradr)|len,i 'kopiert dateinamen in liste + len := strsize(stradr) + repeat i from 0 to len-1 + ios.ram_wrbyte(ios#usrmod,byte[stradr][i],datcnt++) + ios.ram_wrbyte(ios#usrmod,0,datcnt++) + +PRI play_dir_rdlst(stradr)|i,n 'liest dateinamen aus list + i := 0 + repeat + n := ios.ram_rdbyte(ios#usrmod,datcnt++) + byte[stradr][i++] := n + while n <> 0 + +PRI str_find(string_1, string_2) : buffer | counter 'sys: string suchen + +'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +'' │ Searches a string of characters for the first occurence of the specified string of characters. │ +'' │ │ +'' │ Returns the address of that string of characters if found and zero if not found. │ +'' │ │ +'' │ string1 - A pointer to the string of characters to search. │ +'' │ string2 - A pointer to the string of characters to find in the string of characters to search. │ +'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + + repeat strsize(string_1--) + + if(byte[++string_1] == byte[string_2]) + + repeat counter from 0 to (strsize(string_2) - 1) + + if(byte[string_1][counter] <> byte[string_2][counter]) + buffer~~ + + ifnot(buffer~) + return string_1 + +CON + + res_x = 400 + res_y = 300 + + LBASE = 0 + RBASE = res_x - 112 + YBASE = res_y - 112 + + LSHIFT = 8 + +PRI intro + + ball_on(0) + grid_on + pause(3) + bar_on + pause(3) + +PRI boing(stradr)|r,b1,b2,b3,status + + bx := 0 + by := 0 + bxv := 2 + byv := 1 + ball_on(1) + ios.sid_mdmpplay(stradr) ' läuft auf sid2 + repeat + bx += bxv + by += byv + if bx < LBASE + bx := constant(2*LBASE) - bx + -bxv + if bx > RBASE + bx := constant(2*RBASE) - bx + -bxv + if by > YBASE + by := constant(2*YBASE) - by + -byv + ifnot ++r & 7 ' add some gravity + byv++ + status := ios.sid_dmpstatus 'playerstatus abfragen + dmpreg := ios.sid_dmpreg + b1 := (word[dmpreg + 0]>>LSHIFT) #> 1 + b2 := (word[dmpreg + 2]>>LSHIFT) #> 1 + b3 := (word[dmpreg + 4]>>LSHIFT) #> 1 + bars(b1,b2,b3) + setBall(bx,by) + esc_key + waitVBL + while status + ios.sid_dmpstop + +PRI keystat : char + + ios.bus_putchar2(1) + return ios.bus_getchar2 + +PRI waitVBL + + ios.bus_putchar2(4) + +PRI setBall(x,y) + + ios.bus_putchar2(3) + ios.bus_putword2(x) + ios.bus_putword2(y) + +PRI boing_test + + ios.bus_putchar2(5) + +PRI bars(b1,b2,b3) + + ios.bus_putchar2(6) + ios.bus_putchar2(b1) + ios.bus_putchar2(b2) + ios.bus_putchar2(b3) + +PRI grid_on + + ios.bus_putchar2(7) + +PRI grid_off + + ios.bus_putchar2(8) + +PRI show_on + + ios.bus_putchar2(9) + +PRI bar_on + + ios.bus_putchar2(10) + +PRI ball_on(bflag) + + ios.bus_putchar2(11) + ios.bus_putchar2(bflag) + +PRI grid(line,val) + + ios.bus_putchar2(3) + ios.bus_putword2(line) + ios.bus_putword2(val) + +PRI pause(sec) + + waitcnt(cnt + clkfreq * sec) + +DAT + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/gui-demo/GUIBase.spin b/source/gui-demo/GUIBase.spin new file mode 100644 index 0000000..521cf1b --- /dev/null +++ b/source/gui-demo/GUIBase.spin @@ -0,0 +1,938 @@ +CON ''=====< GUI Base >======================================================= +'' +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: GUIBase.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== + +CON + '--------------------------------------------------------------------------- + ' GUI Element Inventory + '--------------------------------------------------------------------------- + ' User modifies these as required by the GUI application being written. + ' These constants describe how many elements of each type are required. Set + ' any you do not need to 1. You can't set it to 0 because there is no + ' conditional compilation for SPIN so I can't avoid NULL references. + '-------------------------------------------------------------------------- + + GZ_SPIN = 2 'number of SPIN controls + GZ_CHKB = 4 'number of Check Boxes + GZ_RADB = 6 'number of Radio Buttons + GZ_TBOX = 3 'number of Text Boxes + GZ_MENU = 6 'number of Menu Items + GZ_INPF = 3 'number of Input Fields + GZ_PUSH = 3 'number of pushbuttons + GZ_STAT = 2 'number of Status Lamps + + + '--------------------------------------------------------------------------- + ' Do not modify any of the constants below + '--------------------------------------------------------------------------- + + GZ_TOTAL = GZ_SPIN+GZ_CHKB+GZ_RADB+GZ_TBOX+GZ_MENU+GZ_INPF+GZ_PUSH+GZ_STAT + + GID_SPIN = $0100 'types + GID_CHKB = $0200 + GID_RADB = $0300 + GID_TBOX = $0400 + GID_MENU = $0500 + GID_INPF = $0600 + GID_PUSH = $0700 + GID_STAT = $0800 + + G_INIT = $8000 + G_IMSK = $7F00 + G_OMSK = $00FF + + VGACOLS = SVGA#cols + VGAROWS = SVGA#rows + + +OBJ + '--------------------------------------------------------------------------- + ' required driver objects, keep these + '--------------------------------------------------------------------------- + SVGA : "vga_hires_text" + MOUS : "mouse" + KEYB : "Keyboard" 'only needed if using the Input Field Object + + '--------------------------------------------------------------------------- + ' UI element objects + ' + ' You will need to comment out elements for which you set the number to 0, + ' the compiler will issue an error for 0 sized arrays. + ' + ' Note that the SBOX object (Simple Box) is used by several other objects so + ' do not comment out that one (it is miniscule anyway) + '--------------------------------------------------------------------------- + SPIN[GZ_SPIN] : "SpinBox" + CHKB[GZ_CHKB] : "RadioCheck" + RADB[GZ_RADB] : "RadioCheck" + TBOX[GZ_TBOX] : "TextBox" + MENU[GZ_MENU] : "MenuItem" + INPF[GZ_INPF] : "InputField" + PUSH[GZ_PUSH] : "PushButton" + STAT[GZ_STAT] : "StatusLamp" + SBOX : "SimpleBox" + + +VAR + long scrn[VGACOLS*VGAROWS/4] 'screen buffer - could be bytes, but longs allow more efficient scrolling + word colors[VGAROWS] 'row colors + long sync 'sync long - written to -1 by VGA driver after each screen refresh + byte cx0,cy0,cm0,cx1,cy1,cm1 'cursor control bytes + long liveINPF 'currently active Input Field (has keyboard focus) + word gz_elem[GZ_TOTAL] 'element management array + byte gz_groups[GZ_RADB] 'radio button group control + +CON ''=====< GUI Base Functions >============================================= + ' + ' NOTE Do not modify anything below unless you wish ot add or + ' make changes to the GUI functionality + '------------------------------------------------------------------------- +PUB Init( vgaBasePin, MouseDatPin, MouseClkPin, KeyboardDatPin, KeyboardClkPin ) | idx, gdx +'Initializes the VGA, Mouse and Keyboard Drivers as well as basic GUI parameters +' +' vgaBasePin - start of 8 consecutive pins where the VGA H/W interface is +' MouseDatPin - the pin driving the mouse data line +' MouseClkPin - the pin driving the mouse clock line +' KeyboardDatPin - the pin driving the keyboard data line +' KeyboardClkPin - the pin driving the keyboard clock line +' +'Returns the screen geometry in a WORD +' high byte = number of character rows +' low byte = number of cgaracter columns + + '--------------------------------------------------------------------------- + ' Start VGA, Mouse and Keyboard Drivers + '--------------------------------------------------------------------------- + + cx1 := 0 'text cursor starting position + cy1 := 3 ' (but hidden at start) + + SVGA.start(vgaBasePin,@scrn,@colors,@cx0,@sync) 'start VGA HI RES TEXT driver + + + MOUS.start(MouseDatPin, MouseClkPin) 'start mouse and set bound parameters + MOUS.bound_limits(0, 0, 0, VGACOLS - 1, VGAROWS - 1, 0) + MOUS.bound_scales(4, -7, 0) 'adjust speed/sensitivity to be a touch slower + MOUS.bound_preset(2, 6, 0) 'mouse starting position + + KEYB.start( KeyboardDatPin, KeyboardClkPin ) 'start keyboard driver + + cm0 := %001 'set mouse cursor to be a solid block + cm1 := %000 'set text cursor to be off for the moment + + ClearScreen( %%020, %%000 ) 'green on black each is %%RGB 4 levels per R-G-B + + + '--------------------------------------------------------------------------- + 'Prepare management and control array. This array has an entry for each + 'element declared it maintains the status of each element and indices into + 'the individual element arrays + ' + 'WORD format: aabb + ' + ' where aa = type with msb 0 = free 1 = set (initialized) + ' bb = index to element array + '--------------------------------------------------------------------------- + + gdx := 0 + + if GZ_SPIN + repeat idx from 0 to GZ_SPIN - 1 + gz_elem[gdx] := GID_SPIN + idx + SPIN[idx].set_gzidx( gdx ) + gdx++ + + if GZ_CHKB + repeat idx from 0 to GZ_CHKB - 1 + gz_elem[gdx] := GID_CHKB + idx + CHKB[idx].set_gzidx( gdx ) + gdx++ + + if GZ_RADB + repeat idx from 0 to GZ_RADB - 1 + gz_elem[gdx] := GID_RADB + idx + RADB[idx].set_gzidx( gdx ) + gdx++ + + if GZ_TBOX + repeat idx from 0 to GZ_TBOX - 1 + gz_elem[gdx] := GID_TBOX + idx + TBOX[idx].set_gzidx( gdx ) + gdx++ + + if GZ_MENU + repeat idx from 0 to GZ_MENU - 1 + gz_elem[gdx] := GID_MENU + idx + MENU[idx].set_gzidx( gdx ) + gdx++ + + if GZ_INPF + repeat idx from 0 to GZ_INPF - 1 + gz_elem[gdx] := GID_INPF + idx + INPF[idx].set_gzidx( gdx ) + gdx++ + + if GZ_PUSH + repeat idx from 0 to GZ_PUSH - 1 + gz_elem[gdx] := GID_PUSH + idx + PUSH[idx].set_gzidx( gdx ) + gdx++ + + if GZ_STAT + repeat idx from 0 to GZ_STAT - 1 + gz_elem[gdx] := GID_STAT + idx + STAT[idx].set_gzidx( gdx ) + gdx++ + + liveINPF := 0 + + return ( VGAROWS << 8 ) + VGACOLS + + +PUB ProcessUI | retVal, gdx_in, odx, idx, tmp +'This function is the UI processing and control funtion. It must be executed +'often, regularly, and quickly. It should be placed in the application main +'loop and be allowed to run as often as possible to ensure a responsive UI +' +'This function will manage the UI and will return the unique id of the GUI +'element that requires an action (i.e. user clicked on an item or pressed +'enter in an Input Field). The value returned ( a GUID ) is the same value +'that was returned when the element was created via "Init" function (i.e. +'from GUI.SPINInit() or GUI.PUSHInit(), etc) + + retVal := -1 + + cx0 := MOUS.bound_x 'get mouse position to set cursor 0 position + cy0 := MOUS.bound_y 'ALWAYS do this first + + '--------------------------------------------------------------------------- + 'check if mouse over a control + '--------------------------------------------------------------------------- + gdx_in := IsIn( cx0, cy0 ) + + '--------------------------------------------------------------------------- + 'on mouse left click perform UI action for selected element (if any) + '--------------------------------------------------------------------------- + if gdx_in <> -1 'if we are in a gui element + if MOUS.button(0) 'if mouse left-click + + odx := gz_elem[gdx_in] & G_OMSK 'index to object array + + case gz_elem[gdx_in] & G_IMSK + GID_SPIN: 'in Spin Control + if SPIN[odx].Clicked(cx0,cy0)<>-1 ' - execute click on spin + retVal := gdx_in + + GID_CHKB: 'in Check Box + CHKB[odx].Select( -1 ) ' - toggle checkbox + retVal := gdx_in + + GID_RADB: 'in Radio Button + idx := 0 + repeat GZ_RADB 'for each radio button + if odx == idx + RADB[idx].Select( 1 ) ' - toggle ON the selected one + RADB[idx].DrawText( 1 ) + else + if gz_groups[odx] == gz_groups[idx] + RADB[idx].Select( 0 ) ' - toggle OFF the others in this group + RADB[idx].DrawText( 0 ) + idx++ + retVal := gdx_in + + GID_TBOX: 'in Text Box + retVal := gdx_in + + GID_MENU: 'in Menu Item + retVal := gdx_in + + GID_INPF: 'in Input Field + idx := 0 + repeat GZ_INPF 'for each input field + if idx == odx + INPF[idx].Select(1,@cx1,@cy1) + liveINPF := idx + cm1 := %111 'turn text cursor on, underscore slow blink + else + INPF[idx].Select(0,@cx1,@cy1) + idx++ + 'note no return for selecting INPF + + GID_PUSH: 'in Push Button + retVal := gdx_in + + GID_STAT: 'in Status Lamp + retVal := gdx_in + + repeat while MOUS.button(0) ' - wait for mouse release + + '--------------------------------------------------------------------------- + 'Handle Keyboard input + '--------------------------------------------------------------------------- + + if KEYB.gotkey + idx := INPF[liveINPF].get_gzidx + if gz_elem[idx] & G_INIT == G_INIT 'is it set + tmp := INPF[liveINPF].Handler(KEYB.key) + if tmp & $80000000 + retVal := INPF[liveINPF].get_gzidx 'if enter was pressed + + return retVal + + +PUB GetMouseXY +'Returns the mouse location in a WORD +' high byte = x location +' low byte = y location + return ( cx0 << 8 ) + cy0 + + +PRI IsIn( cx, cy ) | idx, gdx, retVal +'returns -1 if not in an element else a gui token (gz_elem[] array index) + + retVal := -1 + + if GZ_SPIN + repeat idx from 0 to GZ_SPIN - 1 + gdx := SPIN[idx].get_gzidx + if gz_elem[gdx] & G_INIT == G_INIT 'is it set + if SPIN[idx].IsIn( cx, cy ) + retVal := SPIN[idx].get_gzidx + + if GZ_CHKB + repeat idx from 0 to GZ_CHKB - 1 + gdx := CHKB[idx].get_gzidx + if gz_elem[gdx] & G_INIT == G_INIT 'is it set + if CHKB[idx].IsIn( cx, cy ) + retVal := CHKB[idx].get_gzidx + CHKB[idx].DrawText( 1 ) + else + CHKB[idx].DrawText( 0 ) + + if GZ_RADB + repeat idx from 0 to GZ_RADB - 1 + gdx := RADB[idx].get_gzidx + if gz_elem[gdx] & G_INIT == G_INIT 'is it set + if RADB[idx].IsIn( cx, cy ) + retVal := RADB[idx].get_gzidx + RADB[idx].DrawText( 1 ) + else + RADB[idx].DrawText( 0 ) + + if GZ_TBOX + repeat idx from 0 to GZ_TBOX - 1 + gdx := TBOX[idx].get_gzidx + if gz_elem[gdx] & G_INIT == G_INIT 'is it set + if TBOX[idx].IsIn( cx, cy ) + retVal := TBOX[idx].get_gzidx + + if GZ_MENU + repeat idx from 0 to GZ_MENU - 1 + gdx := MENU[idx].get_gzidx + if gz_elem[gdx] & G_INIT == G_INIT 'is it set + if MENU[idx].IsIn( cx, cy ) + retVal := MENU[idx].get_gzidx + MENU[idx].DrawText( 1 ) + else + MENU[idx].DrawText( 0 ) + + if GZ_INPF + repeat idx from 0 to GZ_INPF - 1 + gdx := INPF[idx].get_gzidx + if gz_elem[gdx] & G_INIT == G_INIT 'is it set + if INPF[idx].IsIn( cx, cy ) + retVal := INPF[idx].get_gzidx + + if GZ_PUSH + repeat idx from 0 to GZ_PUSH - 1 + gdx := PUSH[idx].get_gzidx + if gz_elem[gdx] & G_INIT == G_INIT 'is it set + if PUSH[idx].IsIn( cx, cy ) + retVal := PUSH[idx].get_gzidx + PUSH[idx].DrawText( 1 ) + else + PUSH[idx].DrawText( 0 ) + + if GZ_STAT + repeat idx from 0 to GZ_STAT - 1 + gdx := STAT[idx].get_gzidx + if gz_elem[gdx] & G_INIT == G_INIT 'is it set + if STAT[idx].IsIn( cx, cy ) + retVal := STAT[idx].get_gzidx + + return retVal + + +CON ''=====< SIMPLE BOX INTERFACE FUNCTIONS >================================= + +PUB SBOXInit( pRow, pCol, pWidth, pHeight, pTitlePtr ) +'Creates box with specified width and text. Something like: +' ------------- +' | | - title area ( non-existant if no title supplied) +' ------------- +' | | +' | | - text area with optional scolling print capability +' | | +' ------------- +' +' pRow = row upper location +' pCol = col left location +' pWidth = width +' pHeight = height +' pTitlePtr = title text (text must be 2 less than width) +' +' NOTE: Columns must be LONG aligned to take advantage of the most efficient +' scrolling (via LONGMOVE). The start column must be on a long boundary +' (multiple of 4) and the width must be a multiple of 4. If print scrolling +' is not required this restriction can be ignored. +' +' NOTE: There is NO RETURN value from this call. Simple Boxes are not tracked, +' they are viaual element but are not active elements + SBOX.DrawBox( pRow, pCol, pWidth, pHeight, pTitlePtr, @scrn, VGACOLS ) + + +CON ''=====< SPIN BOX INTERFACE FUNCTIONS >=================================== + +PUB SPINInit( pRow, pCol, pWidth, pType, pNum, pDataPtr ) | idx, gdx, retVal +'Creates a spin button box with specified width and text. Something like: +' --------------------- +' | spin text |↑|↓| +' --------------------- +' +' pRow = row upper location +' pCol = col left location +' pWidth = width of the control in columns +' pType = 0 = text 1 = numeric +' pNum = number of data elements +' pDataPtr = pointer to data for spin control +' +' The Data for the spin control is stored in a DAT section. For text type +' the section will be a number of byte aligned strings, each with a null +' terminator. For numeric type the section will be a number of long aligned +' longs. +' +'Returns -1 if there are no more free elements in the SPIN object array +' guid on success which is unique and used to identify the specific +' instance of the control. + + retVal := -1 + + repeat idx from 0 to GZ_TBOX - 1 + gdx := SPIN[idx].get_gzidx + if gz_elem[gdx] & G_INIT == 0 'is it free + retVal := gdx + gz_elem[gdx] |= G_INIT 'mark it used + SPIN[idx].Init( pRow, pCol, pWidth, pType, pNum, pDataPtr, @scrn, VGACOLS ) + quit + + return retVal + +PUB SPINIsIn( guid ) | odx +' returns true if the mouse is inside the spin control +' false otherwise + + odx := gz_elem[guid] & G_OMSK + return SPIN[odx].IsIn( MOUS.bound_x, MOUS.bound_y ) + +PUB SPINClicked( guid ) | odx +'checks where the mouse click ocurred and returns -1 if not on an UP or DOWN +'arrow otherwise it returns the zero based data index of the currently +'displayed data + + odx := gz_elem[guid] & G_OMSK + return SPIN[odx].Clicked( MOUS.bound_x, MOUS.bound_y ) + +PUB SPINGetDataIndex( guid ) | odx +'returns the zero based index of the currently displayed data item + + odx := gz_elem[guid] & G_OMSK + return SPIN[odx].GetDataIndex + + +CON ''=====< CHECK BOX INTERFACE FUNCTIONS >================================== + +PUB CHKBInit( pRow, pCol, pTextWidth, pTextPtr ) | idx, gdx, retVal +'Creates a checkbox box at the specified location. +'Something like: +' +' X Text here +' +' where X is a check box symbol +' +' pRow = row upper location +' pCol = col left location +' pTextWidth = width of button text (MAX 15 characters) +' pTextPtr = checkbox text (MAX 15 characters) +' +'Returns -1 if there are no more free elements in the CHKB object array +' guid on success which is unique and used to identify the specific +' instance of the control. + + retVal := -1 + + repeat idx from 0 to GZ_CHKB - 1 + gdx := CHKB[idx].get_gzidx + if gz_elem[gdx] & G_INIT == 0 'is it free + retVal := gdx + gz_elem[gdx] |= G_INIT 'mark it used + CHKB[idx].Init( pRow, pCol, pTextWidth, 0, pTextPtr, @scrn, VGACOLS ) + quit + + return retVal + +PUB CHKBIsIn( guid ) | odx +' returns true if the mouse is inside the check box +' false otherwise + odx := gz_elem[guid] & G_OMSK + return CHKB[odx].IsIn( MOUS.bound_x, MOUS.bound_y ) + +PUB CHKBDrawText( guid, pMode ) | odx +' pMode 0 = 0 for normal +' = 1 for inverted + odx := gz_elem[guid] & G_OMSK + CHKB[odx].DrawText( pMode ) + +PUB CHKBSelect( guid, pSel ) | odx +'sel = 1 to select 0 to deselect -1 to toggle it + odx := gz_elem[guid] & G_OMSK + CHKB[odx].Select( pSel ) + + +PUB CHKBIsSet( guid ) | odx +'returns the status of the button (set=true not set=false) + odx := gz_elem[guid] & G_OMSK + return CHKB[odx].isSet + + +CON ''=====< RADIO BUTTON INTERFACE FUNCTIONS >=============================== + +PUB RADBInit( pRow, pCol, pTextWidth, pTextPtr, pGroupID ) | idx, gdx, retVal +'Creates a radio button at the specified location. +'Something like: +' +' X Text here +' +' where X is a radio button symbol +' +' pRow = row upper location +' pCol = col left location +' pTextWidth = width of button text (MAX 15 characters) +' pTextPtr = checkbox text (MAX 15 characters) +' pGroupID = the id of the radio button group that this button belongs to +' +'Returns -1 if there are no more free elements in the RADB object array +' guid on success which is unique and used to identify the specific +' instance of the control. + + retVal := -1 + + repeat idx from 0 to GZ_RADB - 1 + gdx := RADB[idx].get_gzidx + if gz_elem[gdx] & G_INIT == 0 'is it free + retVal := gdx + gz_elem[gdx] |= G_INIT 'mark it used + RADB[idx].Init( pRow, pCol, pTextWidth, 1, pTextPtr, @scrn, VGACOLS ) + gz_groups[idx] := pGroupID 'remember group button belongs to RB_GRP + quit + + return retVal + +PUB RADBIsIn( guid ) | odx +' returns true if the mouse inside the radio button +' false otherwise + odx := gz_elem[guid] & G_OMSK + return RADB[odx].IsIn( MOUS.bound_x, MOUS.bound_y ) + +PUB RADBDrawText( guid, pMode ) | odx +' pMode 0 = 0 for normal +' = 1 for inverted + odx := gz_elem[guid] & G_OMSK + RADB[odx].DrawText( pMode ) + +PUB RADBSelect( guid, pSel ) | odx +'sel = 1 to select 0 to deselect -1 to toggle it + odx := gz_elem[guid] & G_OMSK + RADB[odx].Select( pSel ) + +PUB RADBIsSet( guid ) | odx +'returns the status of the button (set=true not set=false) + odx := gz_elem[guid] & G_OMSK + return RADB[odx].isSet + + +CON ''=====< PUSH BUTTON INTERFACE FUNCTIONS >================================ + +PUB PUSHInit( pRow, pCol, pTextPtr ) | idx, gdx, retVal +'Creates a pushbutton at the specified location. +'Something like: +' --------------- +' |ttttttttttttttt| +' --------------- +' +' where t = button text (MAX 15 characters) +' +' pRow = row upper location +' pCol = col left location +' pTextPtr = push button text (MAX 15 characters + null terminator) +' +'Returns -1 if there are no more free elements in the PUSH object array +' guid on success which is unique and used to identify the specific +' instance of the control. + + retVal := -1 + + repeat idx from 0 to GZ_PUSH - 1 + gdx := PUSH[idx].get_gzidx + if gz_elem[gdx] & G_INIT == 0 'is it free + retVal := gdx + gz_elem[gdx] |= G_INIT 'mark it used + PUSH[idx].Init( pRow, pCol, pTextPtr, @scrn, VGACOLS ) + quit + + return retVal + +PUB PUSHIsIn( guid ) | odx +' returns true if the mouse is inside the push button +' false otherwise + odx := gz_elem[guid] & G_OMSK + return PUSH[odx].IsIn( MOUS.bound_x, MOUS.bound_y ) + +PUB PUSHDrawText( guid, pMode ) | odx +'draws the pusbutton text in normal or inverted video. +' mode bit 0 = 0 for normal +' = 1 for inverted + odx := gz_elem[guid] & G_OMSK + PUSH[odx].DrawText( pMode ) + +PUB PUSHSetText( guid, pPtr ) | odx +'sets new text for the pushbutton +' pPtr points to the text, it MUST be the same size (or less) as the text +' it is replacing + odx := gz_elem[guid] & G_OMSK + PUSH[odx].SetText( pPtr ) + + +CON ''=====< TEXT BOX INTERFACE FUNCTIONS >=================================== + +PUB TBOXInit( pRow, pCol, pWidth, pHeight, pWrap, pTitlePtr ) | idx, gdx, retVal +'Creates a box with specified width and text. Something like: +' ------------- +' | | - title area ( non-existant if no title supplied) +' ------------- +' | | +' | | - text area with optional scolling print capability +' | | +' ------------- +' +' pRow = row upper location +' pCol = col left location +' pWidth = width +' pHeight = height +' pWrap = 0 = truncate 1 = wrap lines +' pTitlePtr = title text text (text must be 2 less than width ore 32 MAX) +' +'Returns -1 if there are no more free elements in the TBOX object array +' guid on success which is unique and used to identify the specific +' instance of the control. +' +' NOTE: Columns must be LONG aligned to take advantage of the most efficient +' scrolling (via LONGMOVE). The start column must be on a long boundary +' (multiple of 4) and the width must be a multiple of 4. If print scrolling +' is not required this restriction can be ignored. + + retVal := -1 + + repeat idx from 0 to GZ_TBOX - 1 + gdx := TBOX[idx].get_gzidx + if gz_elem[gdx] & G_INIT == 0 'is it free + retVal := gdx + gz_elem[gdx] |= G_INIT 'mark it used + TBOX[idx].Init( pRow, pCol, pWidth, pHeight, pWrap, pTitlePtr, @scrn, VGACOLS ) + quit + + return retVal + +PUB TBOXIsIn( guid ) | odx +' returns true if the mouse is inside the text box text area +' (i.e. excluding title area if there is one) +' false otherwise + odx := gz_elem[guid] & G_OMSK + return TBOX[odx].IsIn( MOUS.bound_x, MOUS.bound_y ) + +PUB TBOXClear( guid ) | odx +'clears the text box. + odx := gz_elem[guid] & G_OMSK + TBOX[odx].Clear + +PUB TBOXPrint( guid, pTxtPtr, pSize ) | odx +'Prints a line of text. Iif already at the last row the existing text is +'scrolled up one line first and the top line is removed. Inverted text is +'written with the high bit of each character set. If line wrap is enabled the +'lines that are wrapped are marked with a preceding inverted right arrow +'character (non-printable Ascii). Leading and trailing CRLF characters are +'stripped out. Any intra line CRLFs are ignored and will display as 'funny' +'characters. +' +' pTxtPtr = pointer to null terminated string +' size = 0 for null terminated strings +' = the string length for non-null terminated strings + odx := gz_elem[guid] & G_OMSK + TBOX[odx].Print( pTxtPtr, pSize ) + +PUB TBOXScroll( guid ) | odx +'scroll the test area up one line + odx := gz_elem[guid] & G_OMSK + TBOX[odx].Scroll + +PUB TBOXTitle( guid, pTxtPtr ) | strIdx, vgaIdx, odx +'replace the original titlebar caption with new text. If no title was declared +'on initialization then this method will do nothing +' +' pTxtPtr = pointer to text to place in titlebar + odx := gz_elem[guid] & G_OMSK + TBOX[odx].Title( pTxtPtr ) + + +CON ''=====< MENU ITEM INTERFACE FUNCTIONS >================================== + +PUB MENUInit( pRow, pCol, pTextPtr ) | idx, gdx, retVal +'Creates a menu item at the specified location. +'Something like: +' StttttttttttttttS +' +' where S = space character +' t = character position (MAX 15 characters) +' +' pRow = row upper location +' pCol = col left location +' pTextPtr = menu item text (MAX 15 characters + null terminator) +' +'Returns -1 if there are no more free elements in the MENU object array +' guid on success which is unique and used to identify the specific +' instance of the control. + + retVal := -1 + + repeat idx from 0 to GZ_MENU - 1 + gdx := MENU[idx].get_gzidx + if gz_elem[gdx] & G_INIT == 0 'is it free + retVal := gdx + gz_elem[gdx] |= G_INIT 'mark it used + MENU[idx].Init( pRow, pCol, pTextPtr, @scrn, VGACOLS ) + quit + + return retVal + +PUB MENUIsIn( guid ) | odx +' returns true if the mouse is inside the menu item +' false otherwise + odx := gz_elem[guid] & G_OMSK + return MENU[odx].IsIn( MOUS.bound_x, MOUS.bound_y ) + +PUB MENUDrawText( guid, pMode ) | odx +'draws the menu item text in normal or inverted video. +' mode bit 0 = 0 for normal +' = 1 for inverted + odx := gz_elem[guid] & G_OMSK + MENU[odx].DrawText( pMode ) + +PUB MENUSetText( guid, pPtr ) | odx +'Place new text on the menu item. +' pPtr points to the text, it MUST be the same size (or less) as the text +' it is replacing + odx := gz_elem[guid] & G_OMSK + MENU[odx].SetText( pPtr ) + +PUB MENUSetStatus( guid, pStat ) | odx +'set a user defined status BYTE (any value fro 0 to 255) + odx := gz_elem[guid] & G_OMSK + MENU[odx].SetStatus( pStat ) + +PUB MENUGetStatus( guid ) | odx +'get the use defined status + odx := gz_elem[guid] & G_OMSK + return MENU[odx].GetStatus + + +CON ''=====< INPUT FIELD INTERFACE FUNCTIONS >================================ + +PUB INPFInit(pRow, pCol, pWidth, pType, pTitlePtr ) | idx, gdx, retVal +'Creates an input field box with specified width and text. Something like: +' ----------------------- +' |Title| input field | +' ----------------------- +' +' pRow = row upper location +' pCol = col left location +' pWidth = width of the control in columns +' pType = 0 = standalone 1=tacked on to above +' pHeight = height of the control in rows +' pTitlePtr = title text ( remainder is used for the input field ) +' +'Returns -1 if there are no more free elements in the SPIN object array +' guid on success which is unique and used to identify the specific +' instance of the control. + + retVal := -1 + + repeat idx from 0 to GZ_INPF - 1 + gdx := INPF[idx].get_gzidx + if gz_elem[gdx] & G_INIT == 0 'is it free + retVal := gdx + gz_elem[gdx] |= G_INIT 'mark it used + INPF[idx].Init( pRow, pCol, pWidth, pType, pTitlePtr, @scrn, VGACOLS ) + quit + + return retVal + +PUB INPFIsIn( guid ) | odx +' returns true if the mouse is inside the input field +' false otherwise + odx := gz_elem[guid] & G_OMSK + return INPF[odx].IsIn( MOUS.bound_x, MOUS.bound_y ) + +PUB INPFClear( guid ) | odx +'clear the input field + odx := gz_elem[guid] & G_OMSK + INPF[odx].clear + +PUB INPFSelect( guid, pSel ) | odx +'pSel = 1 to select 0 to deselect -1 to toggle it + odx := gz_elem[guid] & G_OMSK + INPF[odx].Select( pSel, @cx1, @cy1 ) + liveINPF := odx + cm1 := %111 'turn text cursor on, underscore slow blink + +PUB INPFGetString( guid, pBuf ) | odx, tmp, str, len +'places the string in the input field into the buffer provided then clears +'the input field. + odx := gz_elem[guid] & G_OMSK + tmp := INPF[odx].GetStringCode + str := ( tmp & $1FFF0000 ) >> 16 + len := tmp & $000000FF + bytemove( pBuf, @scrn.byte[str], len ) + byte[pBuf][len] := 0 + INPFClear( guid ) + +CON ''=====< STATUS LAMP INTERFACE FUNCTIONS >================================ + +PUB STATInit( pRow, pCol, pWidth, pTitlePtr ) | idx, gdx, retVal +'Creates a status lamp with specified width and text. Something like: +' +' Title : XXXX +' +' where XXXX is user supplied condition status +' +' pRow = row upper location +' pCol = col left location +' pWidth = width of the control in columns +' pHeight = height of the control in rows +' pTitlePtr = title text text (text must be 7 less than width ) +' +'Returns -1 if there are no more free elements in the SPIN object array +' guid on success which is unique and used to identify the specific +' instance of the control. + + retVal := -1 + + repeat idx from 0 to GZ_STAT - 1 + gdx := STAT[idx].get_gzidx + if gz_elem[gdx] & G_INIT == 0 'is it free + retVal := gdx + gz_elem[gdx] |= G_INIT 'mark it used + STAT[idx].Init( pRow, pCol, pWidth, pTitlePtr, @scrn, VGACOLS ) + quit + + return retVal + +PUB STATIsIn( guid ) | odx +' returns true if the mouse is inside the menu item +' false otherwise + odx := gz_elem[guid] & G_OMSK + return STAT[odx].IsIn( MOUS.bound_x, MOUS.bound_y ) + +PUB STATSet( guid, pSet, pStrPtr ) | odx +'pSet = 0 = off mode (uses normal video) +' 1 = on mode (uses inverted video) +'pStr = pointer to status string (4 chars max) + odx := gz_elem[guid] & G_OMSK + STAT[odx].Set( pSet, pStrPtr ) + +PUB STATGetStatus( guid ) | odx +'returns the current status of the object (1=on 0=off) + odx := gz_elem[guid] & G_OMSK + return STAT[odx].GetStatus + + +CON ''===== START OF VGA HIGH RES TEXT SCREEN FUNCTIONS ====================== + +PUB PrintStr( prRow, prCol, strPtr, inv ) | strLen, vgaIdx, idx +'this places text anywhere on the screen and can overwrite UI elements +' +' prRow = row +' prCol = column +' strPtr = pointer to null terminated string +' inv = 0 for normal 1 for inverted video + + if ( prRow < VGAROWS ) AND ( prCol < VGACOLS ) + strLen := strsize( strPtr ) + vgaIdx := prRow * VGACOLS + prCol + bytemove( @scrn.byte[vgaIdx], strPtr, strLen ) + if inv + repeat idx from 1 to strLen + byte[@scrn][vgaIdx] += 128 + vgaIdx++ + +PUB ClearScreen( ForeClr, BackClr ) | wdClr +' This clears the whole screen and sets all rows to the given colours +' ForeClr and BackClr are best represented as quaternary numbers (base 4) +' - these are represented as %%RGB where there are 4 levels for each ( R, G, B) +' - thus entering %%003 is brightest Green + + wdClr := BackClr << 10 + ForeClr << 2 + LONGFILL( @scrn, $20202020, VGACOLS*VGAROWS/4 ) '4 space characters in long + WORDFILL( @colors, wdClr, VGAROWS ) + + +PUB SetLineColor( line, ForeClr, BackClr ) | wdClr +' This sets a single row to the given colours +' ForeClr and BackClr are best represented as quaternary numbers (base 4) +' - these are represented as %%RGB where there are 4 levels for each ( R, G, B) +' - thus entering %%003 is brightest Green + + if line < VGAROWS + wdClr := BackClr << 10 + ForeClr << 2 + colors[line] := wdClr + + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/gui-demo/GUIDemo.spin b/source/gui-demo/GUIDemo.spin new file mode 100644 index 0000000..6159e4a --- /dev/null +++ b/source/gui-demo/GUIDemo.spin @@ -0,0 +1,582 @@ +CON 'Dokumentation, Lizenz +''***********************************/********* +''* VGA High-Res Text UI Elements Demo v1.2 * +''* * +''* File: GUIDemo.spin * +''* Author: Allen Marincak * +''* Copyright (c) 2009 Allen Marincak. * +''* See end of file for terms of use. * +''* * +''* Parts are from a demo by Chip Gracey * +''* Copyright (c) 2006 Parallax, Inc. * +''* Under the same MIT license * +''* ( see end of file ) * +''********************************************* +' +' Notes on the VGA High Res Driver from Chip Gracey's Demo program. +' ---------------------------------------------------------------------------- +' +' 3 June 2006 +' +' This program (a quick piece of junk) demonstrates the VGA_HIRES_TEXT +' object. It is meant for use on the Propeller Demo Board Rev C. You can +' plug in a mouse for screen action. The mouse driver has been upgraded +' to provided bounded mouse coordinates. This makes constrained and +' scaled mouse movement mindless. +' +' The VGA_HIRES_TEXT went through much metamorphosis before completion. +' Initially, it ran on five COGs! I thought this was a miracle, since I +' didn't think we'd be able to get such high-res displays on the current +' Propeller chip. It used four COGs to build scan lines, and a fifth COG +' to display them. I kept looking at the problem and realized that it +' all came down to how little monkeying could be done with the data in +' order to display it. The scan line building was reorganized so that a +' single RDLONG picks up four lines worth of pixels for a character, and +' then buffers them within the COG, to later output them with back-to- +' back 'WAITVID color,pixels' and 'SHR pixels,#8' instruction sequences. +' This was so much faster that only two COGs were required for the job! +' They had to be synchronized so that they could step seamlessly into +' eachother's shoes as they traded the tasks of building scan lines and +' then displaying them. Anyway, it all came together nicely. + +' Note that the driver has different VGA mode settings which you can de- +' comment and try. Also, the driver contains its own font. You will see +' the character set printed out when you run the program. There are some +' characters within the font that provide quarter-character-cell block +' pixels (for 128x64 characters, you can get 256x128 'pixels'). They can +' be used for graphing or crude picture drawing, where text can be inter- +' mingled. +' +' If you have a 15" LCD monitor, you must see the 1024x768 mode on it. +' At least on my little Acer AL1511 monitor, every pixel locks perfectly. +' +'----------------------------------------------------------------------------- +' +' Allen Marincak Feb 2009 Demo program Notes +' +' Chip states above that this demo is for use on the Propeller Demo Board. It +' will however work on any Propeller board with VGA and Mouse driver +' functionality. +' +' The info above was from the VGA_HiRes_Text demo program Chip Gracey wrote. +' There is nothing of consequence left here of that file but the VGA Driver +' driver itself remains intact. *This* demo is setup to show how to use some +' very simple text based graphical user interface elements written for the VGA +' HiRes Text mode. It is an ultra trivial implementation, with virtually no +' error checking so heads up! I did this on purpose to keep it lean. After the +' VGA driver uses some 6K to 10K bytes of memory and 2 cogs to display text I +' did not want to use up most of the rest of the memory with a boatload of +' error checking and a fancier UI on its own COG. I opted to leave as much +' memory as possible for applications that could benefit from cheap and simple +' buttons, menus, text panels and such. Especially since one needs the Mouse +' and Keyboard drivers as well, each of these take up 1 more COG. After loading +' those drivers and creating 10 or so UI elements you will have 2/3 to 1/2 of +' available memory left for your application (depending on VGA Resolution +' desired, I tend to use 800x600 as a good compromise between memory and real +' estate). +' +' There are several UI elements implemented, you stitch together what you need +' and lay it out how you want to use it. There are 9 objects (well 8, the Radio +' Button and Check Box objects are both from the RadioCheck.spin object), and +' some glue functions in the package (in GUIBase.spin). The UI elements are +' rudimentary and lean but provide adequate funtionality for many control and +' monitoring applications. I did not implement repositioning the items, any +' buffering of data in text boxes, pop-up windows or drop down lists, etc. +' These would just use up more memory and I was after a simple light-weight +' (thereby static) UI to provide simple control and feedback for some of my +' projects. +' +' +' SimpleBox.spin +' - draws boxes in the area specified, with or without a "title bar" +' - useful to visually group and organize other control +' +' RadioCheck.spin +' - creates Check Box and Radio Button controls +' +' TextBox.spin +' - creates simple text windows controls that are line based. +' - truncates or wraps lines into the window pane +' - optional (but useful) titlebar avaiable +' +' MenuItem.spin +' - simple text "button" that to create a rudimentary menubar. +' +' PushButton.spin +' - creates a straightforward pushbutton +' +' InputField.spin +' - creates a one line input field with a caption / title. There is only +' simple editing via backspace. +' - keyboard input focus can be switched between controls on the fly with +' mouse click +' +' SpinBox.spin +' - created straight forward spin button controls +' +' StatusLamp.spin +' - a simple annunciator 'lamp' for condition feedback +' +' GUIBase.spin +' - This is actually the main interface to the GUI objects +' - you call functions here, not in the object files themselves +' - GUI initialization and processing is done with functions here +' - Init() starts VGA, Mouse, and Keyboard drivers and initializes +' data structures used by the UI +' - ProcessUI() manages the UI infrastructure you must call this in +' your main loop regularly for a responsive UI. It +' returns ID of elements that require actionm (i.e. +' the mouse was clicked on a Push Button, etc). +' +' Memory requirements with UI +' - 1/3 to 1/2 of RAM depending on VGA resolution +' +' COGS used +' - the UI does not use a new COG it runs out of the main app's COG. +' - 2 COGS for the High Res VGA Text driver +' - 1 COG for the Mouse Driver +' - 1 COG for the Keyboard Driver (optional, for Input Field Object only) +' +'----------------------------------------------------------------------------- + +CON + + _clkmode = xtal1 + pll16x + _xinfreq = 5_000_000 + + vga_base = 8 'VGA - VSync + + mouse_dat = 19 'MOUSE data + mouse_clk = 18 'MOUSE clock + keyboard_dat = 17 'KEYBOARD data + keyboard_clk = 16 'KEYBOARD clock + + +OBJ + '--------------------------------------------------------------------------- + ' UI element objects YOU NEED THIS + '--------------------------------------------------------------------------- + GUI : "GUIBase" 'starts VGA, Mouse, & Keyboard drivers + + '--------------------------------------------------------------------------- + ' Auxiliary objects (these are just used in the demo app only) + '--------------------------------------------------------------------------- + TMRS : "Timer" + NUMS : "simple_numbers" + + +VAR + '--------------------------------------------------------------------------- + ' UI element IDs YOU MUST HAVE THESE to remember the GUI ID's (guid) of the + ' elements you create. In this demo APP there are 29 items, + ' your application will have more or fewer (as required). + ' These are returned by the element Init() calls + ' ( i.e. CHKB1 := GUI.CHKBInit(..) ) + '--------------------------------------------------------------------------- + byte CHKB1 + byte CHKB2 + byte CHKB3 + byte CHKB4 + byte RADB1 + byte RADB2 + byte RADB3 + byte RADB4 + byte RADB5 + byte RADB6 + byte TBOX1 + byte TBOX2 + byte TBOX3 + byte MENU1 + byte MENU2 + byte MENU3 + byte MENU4 + byte MENU5 + byte MENU6 + byte INPF1 + byte INPF2 + byte INPF3 + byte PUSH1 + byte PUSH2 + byte PUSH3 + byte STAT1 + byte STAT2 + byte SPIN1 + byte SPIN2 + + '--------------------------------------------------------------------------- + ' Screen Geometry returned by call to GUI.Init() (may be useful) + '--------------------------------------------------------------------------- + byte vga_rows, vga_cols + + '--------------------------------------------------------------------------- + ' variables used by local main loop processing, not required by library + ' functions. You can get rid of these when creating your own app. + '--------------------------------------------------------------------------- + long cnt1 'line counter for textbox 1 + long cnt2 'line counter for textbox 2 + long clrCnt 'clear textbox counter + long random 'random number seed + long logging 'logging flag + byte strBuf[36] + byte strBuf2[64] + + +PUB start | gx, tmr1, tmr2, idx, str, tmp + + '--------------------------------------------------------------------------- + 'Some houskeeping ... timers and "logging" status + 'This TIMER object started here is used for this demo only. It is used to + 'periodically trigger printing to text boxes to simulate "live text" comming + 'in. It is not needed by the UI stuff and you don't need it in your program + 'unless you want a timer object to do timed activity. Note that it uses a + 'separate COG (so it is not cheap). + '--------------------------------------------------------------------------- + TMRS.start( 10 ) 'start timer object (1/10 sec timer) + tmr1 := TMRS.register 'register 2 timers + tmr2 := TMRS.register + + logging := 1 'logging is on to start + + + '--------------------------------------------------------------------------- + ' Create the UI + '--------------------------------------------------------------------------- + CreateUI + + + '--------------------------------------------------------------------------- + 'some final non UI related houskeeping ... + '--------------------------------------------------------------------------- + TMRS.set( tmr1, 10 ) 'start 1 second timeout + TMRS.set( tmr2, 17 ) 'start 1.7 second timeout + + + '--------------------------------------------------------------------------- + ' Everything is setup, now the MAIN LOOP begins ... + '--------------------------------------------------------------------------- + repeat + gx := GUI.ProcessUI 'process the UI + + case gx 'handle GUI Events ( Mouse click or Enter Key in Input Field ) + + CHKB1: UserDoSomethingFunction( gx ) + + CHKB2: UserDoSomethingFunction( gx ) + + CHKB3: UserDoSomethingFunction( gx ) + + CHKB4: UserDoSomethingFunction( gx ) + + RADB1: UserDoSomethingFunction( gx ) + + RADB2: UserDoSomethingFunction( gx ) + + RADB3: UserDoSomethingFunction( gx ) + + RADB4: UserDoSomethingFunction( gx ) + + RADB5: UserDoSomethingFunction( gx ) + + RADB6: UserDoSomethingFunction( gx ) + + MENU1: DoMenu1Action + + MENU2: DoMenu2Action + + MENU3: DoMenu3Action + + MENU4: DoMenu4Action + + MENU5: DoMenu5Action + + MENU6: DoMenu6Action + + PUSH1: UserDoSomethingFunction( gx ) + + PUSH2: UserDoSomethingFunction( gx ) + + PUSH3: UserDoSomethingFunction( gx ) + + SPIN1: UserDoSomethingFunction( gx ) + + SPIN2: UserDoSomethingFunction( gx ) + + INPF1: DoInputFieldAction( INPF1 ) + + INPF2: DoInputFieldAction( INPF2 ) + + INPF3: DoInputFieldAction( INPF3 ) + + + '---------------------------------------------------------------------- + 'user application code goes here or after the ProcessUI call (but still + 'within the REPEAT loop!). + '---------------------------------------------------------------------- + idx := GUI.GetMouseXY + GUI.PrintStr( vga_rows-1, 15, NUMS.decf( idx >> 8, 2 ), 0 ) + GUI.PrintStr( vga_rows-1, 20, NUMS.decf( idx & $FF, 2 ), 0 ) + + if TMRS.isClr( tmr2 ) 'if timer 2 expired write line text into textbox 2 + TMRS.set( tmr2, 17 ) + cnt2++ + bytemove( @strBuf, string( "Text # " ), 7 ) + str := NUMS.dec( cnt2 ) + tmp := strsize( str ) + 1 + bytemove( @strBuf[7], str, tmp ) + GUI.TBOXPrint( TBOX2, @strBuf, 0 ) + + if logging == 1 + if TMRS.isClr( tmr1 ) 'if timer 1 expired write line text into textbox 1 + TMRS.set( tmr1, 10 ) + cnt1++ + bytemove( @strBuf, string( "This is line number " ), 20 ) + str := NUMS.dec( cnt1 ) + tmp := strsize( str ) + 1 + bytemove( @strBuf[20], str, tmp ) + GUI.TBOXPrint( TBOX1, @strBuf, 0 ) + + + +CON ''=====< START OF UI HELPER FUNTIONS >================================== +PRI CreateUI | tmp +'You create this function to create your GUI. +' +'This function is called during startup to create and position the UI elements +'that you will use. The total number of UI elements of each type must be +'declared in the OBJ section (i.e. if you need 5 pushbuttons, delcare an array +'of 5 pushbutton objects). + + '--------------------------------------------------------------------------- + 'Initialize GUI, starts VGA, Mouse, and Keyboard Drivers + ' + 'YOU MUST DO THIS FIRST (saving screen geometry is optional) + '--------------------------------------------------------------------------- + tmp := GUI.Init(vga_base, mouse_dat, mouse_clk, keyboard_dat, keyboard_clk ) + vga_rows := ( tmp & $0000FF00 ) >> 8 + vga_cols := tmp & $000000FF + + + '--------------------------------------------------------------------------- + 'setup screen colours + '--------------------------------------------------------------------------- + GUI.ClearScreen( %%020, %%000 ) 'green on black each is %%RGB 4 levels per R-G-B + GUI.SetLineColor( 0, %%000, %%333 ) 'Menu Area colour Line 1 + GUI.SetLineColor( 1, %%000, %%333 ) 'Menu Area colour Line 2 + GUI.SetLineColor( 2, %%000, %%333 ) 'Menu Area colour Line 3 + + repeat tmp from 3 to vga_rows-16 + GUI.SetLineColor( tmp, %%111, %%333 ) 'Console Window colour + + repeat tmp from vga_rows-15 to vga_rows-2 + GUI.SetLineColor( tmp, %%111, %%333 ) 'Console Window colour + + GUI.SetLineColor(vga_rows-1,%%111,%%333) 'Status Line colour + + + '--------------------------------------------------------------------------- + 'put up some menu items + '--------------------------------------------------------------------------- + GUI.SBOXInit( 0, 0, vga_cols, 3, 0 ) 'menu group box + MENU1 := GUI.MENUInit(1, 3,string(" Open Port ")) 'Menu Items setup + MENU2 := GUI.MENUInit(1,19,string("Stop Logging")) + MENU3 := GUI.MENUInit(1,35,string("New Text Box")) + MENU4 := GUI.MENUInit(1,51,string("Chk Battery ")) + MENU5 := GUI.MENUInit(1,67,string("Read Sensors")) + MENU6 := GUI.MENUInit(1,83,string(" Clear Log ")) + GUI.MENUSetStatus( MENU2, logging ) + + + '--------------------------------------------------------------------------- + 'put up some check boxes + '--------------------------------------------------------------------------- + GUI.SBOXInit( 11, 4, 18, 8, string("Terminal")) 'checkbox group box + CHKB1 := GUI.CHKBInit( 14, 6, 12, string( "7-bit ASCII" ) ) + CHKB2 := GUI.CHKBInit( 15, 6, 12, string( "Show Cursor" ) ) + CHKB3 := GUI.CHKBInit( 16, 6, 12, string( "Local Echo" ) ) + CHKB4 := GUI.CHKBInit( 17, 6, 12, string( "Append LF" ) ) + GUI.CHKBSelect( CHKB3, 1 ) 'select this one as the group's startup default + + + '--------------------------------------------------------------------------- + 'put up some radio buttons + '--------------------------------------------------------------------------- + GUI.SBOXInit( 20, 4, 18, 10, string("Baud Rate")) 'radio button group box + RADB1 := GUI.RADBInit( 23, 6, 11, string( "115200" ), 0 ) + RADB2 := GUI.RADBInit( 24, 6, 11, string( "57600 " ), 0 ) + RADB3 := GUI.RADBInit( 25, 6, 11, string( "19200 " ), 0 ) + RADB4 := GUI.RADBInit( 26, 6, 11, string( "9600 " ), 0 ) + RADB5 := GUI.RADBInit( 27, 6, 11, string( "4800 " ), 0 ) + RADB6 := GUI.RADBInit( 28, 6, 11, string( "1200 " ), 0 ) + GUI.RADBSelect( RADB4, 1 ) 'select this one as the group's startup default + + + '--------------------------------------------------------------------------- + 'put up some status lamps + '--------------------------------------------------------------------------- + GUI.SBOXInit( 4,4,18,6,string("Status") ) 'status lamp group box + STAT1 := GUI.STATInit( 7,6, 14, string( "Logging" ) ) + STAT2 := GUI.STATInit( 8,6, 14, string( " Port" ) ) + GUI.STATSet( STAT1, 1, string("ON") ) + GUI.STATSet( STAT2, 0, string("OFF") ) + + + '--------------------------------------------------------------------------- + 'put up some text boxes, one without a title + '--------------------------------------------------------------------------- + TBOX1 := GUI.TBOXInit( 4,28,36,26,1,string("Logging Window") ) + TBOX2 := GUI.TBOXInit(10,70,24,20,1,0 ) + TBOX3 := GUI.TBOXInit(vga_rows-25,4,90,22,1,string("Console Window") ) + cnt1 := 0 'line counter for textbox 1 + cnt2 := 0 'line counter for textbox 2 + clrCnt := 0 'clear textbox counter + random := 0 'random number seed + + + '--------------------------------------------------------------------------- + 'put up a couple of input fields + '--------------------------------------------------------------------------- + INPF1 := GUI.INPFInit( 4, 70, 24, 0, string("Speed") ) + INPF2 := GUI.INPFInit( 31, 4, 60, 0, string("Message") ) + INPF3 := GUI.INPFInit( vga_rows-4, 4, 90, 1, string("Command") ) + GUI.INPFSelect( INPF3, 1 ) + + '--------------------------------------------------------------------------- + 'put up some push buttons + '--------------------------------------------------------------------------- + PUSH1 := GUI.PUSHInit( 7, 70, string( "Slower" ) ) + PUSH2 := GUI.PUSHInit( 7, 78, string( " Stop " ) ) + PUSH3 := GUI.PUSHInit( 7, 86, string( "Faster" ) ) + + + '--------------------------------------------------------------------------- + 'put up some spin buttons + '--------------------------------------------------------------------------- + SPIN1 := GUI.SPINInit( 31, 70, 24, 0, 4, @SpinDat0 ) 'languages + SPIN2 := GUI.SPINInit( 34, 70, 24, 1, 10, @SpinDat1 ) 'log scale + + + '--------------------------------------------------------------------------- + 'Put something in the status bar (just the mouse coordinates in this demo) + '--------------------------------------------------------------------------- + GUI.PrintStr(vga_rows-1,0,string( "Status Line: X=xx Y=xx" ), 0 ) + + +PRI UserDoSomethingFunction( val ) ' - USER ACTION FUNCTION +'this is a dummy ... in a real app the user would have one of these for each +'UI action that required some activity. For this Demo where the user would +'normally call their own function I just call this dummy placeholder instead. + GUI.TBOXPrint( TBOX3, string( "Normally a user function would be called." ), 0 ) + return val + + +PRI DoMenu1Action | mStat + + mStat := GUI.MENUGetStatus( MENU1 ) 'get current user status of menu item + + if mStat == 0 + GUI.TBOXPrint( TBOX3, string( "Opened port."), 0 ) 'announce activity to console window + GUI.MENUSetText( MENU1, string( "Close Port" ) ) 'change the menu item text + GUI.MENUSetStatus( MENU1, 1 ) 'set new status of the menu item + GUI.STATSet( STAT2, 1, string("OPEN") ) 'set status lamp ON + else + GUI.TBOXPrint( TBOX3, string( "Closed port." ), 0 ) 'announce activity to console window + GUI.MENUSetText( MENU1, string( " Open Port" ) ) 'change the menu item text + GUI.MENUSetStatus( MENU1, 0 ) 'set new status of the menu item + GUI.STATSet( STAT2, 0, string("OFF") ) 'set status lamp OFF + + +PRI DoMenu2Action | mStat + + mStat := GUI.MENUGetStatus( MENU2 ) 'get current user status of menu item + + if mStat == 0 + GUI.TBOXPrint( TBOX3, string("Started Logging."),0) 'announce activity to console window + GUI.MENUSetText( MENU2, string( "Stop Logging" )) 'change the menu item text + GUI.MENUSetStatus( MENU2, 1 ) 'set new status of the menu item + GUI.STATSet( STAT1, 1, string("ON") ) 'set status lamp ON + logging := 1 + else + GUI.TBOXPrint(TBOX3,string("Stopped logging." ),0) 'announce activity to console window + GUI.MENUSetText( MENU2, string( " Log Data " ) ) 'change the menu item text + GUI.MENUSetStatus( MENU2, 0 ) 'set new status of the menu item + GUI.STATSet( STAT1, 0, string("OFF") ) 'set status lamp OFF + logging := 0 + + +PRI DoMenu3Action + GUI.TBOXPrint( TBOX1, @longstring, 0 ) + GUI.TBOXPrint( TBOX2, @longstring, 0 ) + GUI.SBOXInit( 12, 36, 14, 10, string("New Text Box")) 'create new simple box + + +PRI DoMenu4Action | rnd + rnd := ?random / 100_000_000 + rnd *= rnd 'formulate a random number + bytemove( @strbuf, string( "Battery = 9." ), 12 ) + bytemove( @strbuf[12], NUMS.decx( rnd, 3 ), 3 ) + bytemove( @strbuf[15], string( " vdc." ), 4 ) + strbuf[19] := 0 + GUI.TBOXPrint(TBOX3, @strbuf, 0 ) 'display 'voltage' in console window + + +PRI DoMenu5Action + GUI.TBOXPrint(TBOX3,string("Sensors are not ready."),0) 'announce activity to console window + + +PRI DoMenu6Action | tmp + GUI.TBOXClear( TBOX1 ) 'ACTION: clear the text box + bytemove(@strBuf,string("Logging Window Cleared "),24) 'create new text box title + clrCnt++ + bytemove(@strBuf[24],NUMS.decf(clrCnt,3),3) 'tack on cleared count + tmp := 16 + repeat while strBuf[tmp] <> 0 'make cleared count text inverted + strBuf[tmp++] += 128 + GUI.TBOXTitle( TBOX1, @strBuf ) 'put new title in text box + + +PRI DoInputFieldAction( guid ) + GUI.INPFGetString( guid, @strBuf2 ) + GUI.TBOXPrint(TBOX3, @strbuf2, 0 ) 'display 'voltage' in console window + + + +DAT + +longstring byte 13,10,"This is a long string. It will take up ",13,10,"several lines. The leading and trailing CRLF should be stripped off but not the one inside the string.",13,10,0 + + +'----------------------------------------------------------------------------- +'Data for the spin buttons. Text type spin buttons will have an array of null +'terminated stings here. Numeric type spin buttons will have an array of long +'values. +'----------------------------------------------------------------------------- +SpinDat0 byte "English",0 + byte "French",0 + byte "Spanish", 0 + byte "Slovak", 0 + +SpinDat1 long 1,2,5,10,20,50,100,200,500,1000 + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/gui-demo/InputField.spin b/source/gui-demo/InputField.spin new file mode 100644 index 0000000..aa26eec --- /dev/null +++ b/source/gui-demo/InputField.spin @@ -0,0 +1,194 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: InputField.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +''============================================================================ +'' Simple Keyboard Input Handler +''============================================================================ +'' +'' Creates a simple one line input field. The input field manages characters +'' from the keyboard. The contol was designed for simple commands or value +'' entry. The only editing is via the backspace key. The enter key signals +'' completion and it is up to the calling application to do as required with +'' the input. + + +OBJ + SBOX : "SimpleBox" + + +VAR + word varGdx 'GUI control variable + long varVgaPos 'screen location of start of input area + long varScreenPtr 'screen buffer pointer + long varCxPtr 'points to the text cursor x position variable + byte varRow 'top row location + byte varCol 'left col location + byte varCol2 'right col location + byte varWidth 'width ... text width is 2 less than total width + byte varTitleWidth 'number of rows used for title area ( 0 or 2 ) + byte varStatus '0 = unselected 1 = selected + byte varColIdx 'index to current col to be written + byte varCursorCol 'column the text cursor is in + byte varVgaCols 'width of screen in columns + + +PUB Init ( pRow, pCol, pWidth, pType, pTitlePtr, pVgaPtr, pVgaWidth ) | vgaIdx + + varVgaCols := pVgaWidth + varRow := pRow + varCol := pCol + varWidth := pWidth + varTitleWidth := strsize( pTitlePtr ) + varColIdx := 0 + varScreenPtr := pVgaPtr + varCol2 := varCol + varWidth + varCxPtr := 0 + varCursorCol := varCol + varTitleWidth + varColIdx + 2 + + SBOX.DrawBox( pRow, pCol, pWidth, 3, 0, pVgaPtr, pVgaWidth ) + + vgaIdx := varRow * varVgaCols + varCol + + if pType == 1 + byte[varScreenPtr][vgaIdx] := 18 'left 'tee' char + byte[varScreenPtr][vgaIdx+pWidth-1] := 19 'right 'tee' char + + vgaIdx += varTitleWidth + 1 + + byte[varScreenPtr][vgaIdx] := 16 'top 'tee' char + vgaIdx += varVgaCols + byte[varScreenPtr][vgaIdx] := 15 'vertical line char + vgaIdx += varVgaCols + byte[varScreenPtr][vgaIdx] := 17 'bottom 'tee' char + + vgaIdx -= ( varVgaCols + varTitleWidth ) + bytemove( @byte[varScreenPtr][vgaIdx], pTitlePtr, varTitleWidth ) + + varVgaPos := (varRow+1)*varVgaCols+varCol+2+varTitleWidth 'save input area start + + +PUB Handler( pKeyCode ) | retVal, vgaIdx +'Handles key codes for a basic one line input field intended for simple data +'or commands (it is not a text editor :-)). The control uses the screen as a +'buffer so no extra memory is required to pass back the data to the caller. +'When the user presses enter a return value is bitfield encoded containing +'the address and size of the text entered. The caller then must get or use the +'data entered and then call the CLEAR method to reset the input field. +' +' returns 0 = ok, no action required +' 1 = not selected +' MSB set = enter pressed, caller to read string and clear field +' Returned word is bitfield encoded to return the address +' and size of the string entered. Encoded as follows: +' %100a_aaaa_aaaa_aaaa_0000_0000_ssss_ssss +' a = 13bit address s = 8 bit size +' + retVal := 0 + vgaIdx := varVgaPos + varColIdx + + if varStatus == 0 + retVal := 1 + else + case pKeyCode + $20 .. $7E: 'standard ASCII characters + if varColIdx < varWidth - 3 - varTitleWidth + byte[varScreenPtr][vgaIdx] := pKeyCode + varColIdx++ + varCursorCol++ + byte[varCxPtr][0] := varCursorCol 'move text cursor + + $0D: 'carriage return + retval := $80000000 ' set MSB + + $C8: 'backspace + if ( varColIdx ) + vgaIdx-- + varColIdx-- + varCursorCol-- + byte[varScreenPtr][vgaIdx] := " " + byte[varCxPtr][0] := varCursorCol 'move text cursor + + return retVal + + +PUB IsIn( pCx, pCy ) | retVal + + retVal := false + + if ( pCx => varCol ) AND ( pCx =< varCol2 ) + if pCy == varRow + 1 + retVal := true + + return retVal + + +PUB clear + bytefill( @byte[varScreenPtr][varVgaPos], 32, varWidth - varTitleWidth - 3 ) + varColIdx := 0 + varCursorCol := varCol + varTitleWidth + varColIdx + 2 + byte[varCxPtr][0] := varCursorCol 'move text cursor + + +PUB Select( pSel, pCxPtr, pCyPtr ) + + if pSel <> -1 + varStatus := pSel + else + if varStatus == 0 + varStatus := 1 + else + varStatus := 0 + + if varStatus == 1 + varCxPtr := pCxPtr + byte[varCxPtr][0] := varCursorCol + byte[pCyPtr][0] := varRow + 1 + + +PUB GetStringCode | retval + + retval := varVgaPos << 16 ' encode address + retval |= $80000000 ' set MSB + retval += varColIdx ' set size + + return retval + + +PUB set_gzidx( gzidx ) + varGdx := gzidx + + +PUB get_gzidx + return varGdx + + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/Keyboard.spin b/source/gui-demo/Keyboard.spin new file mode 100644 index 0000000..5908c79 --- /dev/null +++ b/source/gui-demo/Keyboard.spin @@ -0,0 +1,736 @@ +''*************************************** +''* PS/2 Keyboard Driver v1.0.1 * +''* Author: Chip Gracey * +''* Copyright (c) 2004 Parallax, Inc. * +''* See end of file for terms of use. * +''*************************************** + +{-----------------REVISION HISTORY----------------- + v1.0.1 - Updated 6/15/2006 to work with Propeller Tool 0.96} + +VAR + + long cog + + long par_tail 'key buffer tail read/write (19 contiguous longs) + long par_head 'key buffer head read-only + long par_present 'keyboard present read-only + long par_states[8] 'key states (256 bits) read-only + long par_keys[8] 'key buffer (16 words) read-only (also used to pass initial parameters) + + +PUB start(dpin, cpin) : okay + +'' Start keyboard driver - starts a cog +'' returns false if no cog available +'' +'' dpin = data signal on PS/2 jack +'' cpin = clock signal on PS/2 jack +'' +'' use 100-ohm resistors between pins and jack +'' use 10K-ohm resistors to pull jack-side signals to VDD +'' connect jack-power to 5V, jack-gnd to VSS +'' +'' all lock-keys will be enabled, NumLock will be initially 'on', +'' and auto-repeat will be set to 15cps with a delay of .5s + + okay := startx(dpin, cpin, %0_000_100, %01_01000) + + +PUB startx(dpin, cpin, locks, auto) : okay + +'' Like start, but allows you to specify lock settings and auto-repeat +'' +'' locks = lock setup +'' bit 6 disallows shift-alphas (case set soley by CapsLock) +'' bits 5..3 disallow toggle of NumLock/CapsLock/ScrollLock state +'' bits 2..0 specify initial state of NumLock/CapsLock/ScrollLock +'' (eg. %0_001_100 = disallow ScrollLock, NumLock initially 'on') +'' +'' auto = auto-repeat setup +'' bits 6..5 specify delay (0=.25s, 1=.5s, 2=.75s, 3=1s) +'' bits 4..0 specify repeat rate (0=30cps..31=2cps) +'' (eg %01_00000 = .5s delay, 30cps repeat) + + stop + longmove(@par_keys, @dpin, 4) + okay := cog := cognew(@entry, @par_tail) + 1 + + +PUB stop + +'' Stop keyboard driver - frees a cog + + if cog + cogstop(cog~ - 1) + longfill(@par_tail, 0, 19) + + +PUB present : truefalse + +'' Check if keyboard present - valid ~2s after start +'' returns t|f + + truefalse := -par_present + + +PUB key : keycode + +'' Get key (never waits) +'' returns key (0 if buffer empty) + + if par_tail <> par_head + keycode := par_keys.word[par_tail] + par_tail := ++par_tail & $F + + +PUB getkey : keycode + +'' Get next key (may wait for keypress) +'' returns key + + repeat until (keycode := key) + + +PUB newkey : keycode + +'' Clear buffer and get new key (always waits for keypress) +'' returns key + + par_tail := par_head + keycode := getkey + + +PUB gotkey : truefalse + +'' Check if any key in buffer +'' returns t|f + + truefalse := par_tail <> par_head + + +PUB clearkeys + +'' Clear key buffer + + par_tail := par_head + + +PUB keystate(k) : state + +'' Get the state of a particular key +'' returns t|f + + state := -(par_states[k >> 5] >> k & 1) + + +DAT + +'****************************************** +'* Assembly language PS/2 keyboard driver * +'****************************************** + + org +' +' +' Entry +' +entry movd :par,#_dpin 'load input parameters _dpin/_cpin/_locks/_auto + mov x,par + add x,#11*4 + mov y,#4 +:par rdlong 0,x + add :par,dlsb + add x,#4 + djnz y,#:par + + mov dmask,#1 'set pin masks + shl dmask,_dpin + mov cmask,#1 + shl cmask,_cpin + + test _dpin,#$20 wc 'modify port registers within code + muxc _d1,dlsb + muxc _d2,dlsb + muxc _d3,#1 + muxc _d4,#1 + test _cpin,#$20 wc + muxc _c1,dlsb + muxc _c2,dlsb + muxc _c3,#1 + + mov _head,#0 'reset output parameter _head +' +' +' Reset keyboard +' +reset mov dira,#0 'reset directions + mov dirb,#0 + + movd :par,#_present 'reset output parameters _present/_states[8] + mov x,#1+8 +:par mov 0,#0 + add :par,dlsb + djnz x,#:par + + mov stat,#8 'set reset flag +' +' +' Update parameters +' +update movd :par,#_head 'update output parameters _head/_present/_states[8] + mov x,par + add x,#1*4 + mov y,#1+1+8 +:par wrlong 0,x + add :par,dlsb + add x,#4 + djnz y,#:par + + test stat,#8 wc 'if reset flag, transmit reset command + if_c mov data,#$FF + if_c call #transmit +' +' +' Get scancode +' +newcode mov stat,#0 'reset state + +:same call #receive 'receive byte from keyboard + + cmp data,#$83+1 wc 'scancode? + + if_nc cmp data,#$AA wz 'powerup/reset? + if_nc_and_z jmp #configure + + if_nc cmp data,#$E0 wz 'extended? + if_nc_and_z or stat,#1 + if_nc_and_z jmp #:same + + if_nc cmp data,#$F0 wz 'released? + if_nc_and_z or stat,#2 + if_nc_and_z jmp #:same + + if_nc jmp #newcode 'unknown, ignore +' +' +' Translate scancode and enter into buffer +' + test stat,#1 wc 'lookup code with extended flag + rcl data,#1 + call #look + + cmp data,#0 wz 'if unknown, ignore + if_z jmp #newcode + + mov t,_states+6 'remember lock keys in _states + + mov x,data 'set/clear key bit in _states + shr x,#5 + add x,#_states + movd :reg,x + mov y,#1 + shl y,data + test stat,#2 wc +:reg muxnc 0,y + + if_nc cmpsub data,#$F0 wc 'if released or shift/ctrl/alt/win, done + if_c jmp #update + + mov y,_states+7 'get shift/ctrl/alt/win bit pairs + shr y,#16 + + cmpsub data,#$E0 wc 'translate keypad, considering numlock + if_c test _locks,#%100 wz + if_c_and_z add data,#@keypad1-@table + if_c_and_nz add data,#@keypad2-@table + if_c call #look + if_c jmp #:flags + + cmpsub data,#$DD wc 'handle scrlock/capslock/numlock + if_c mov x,#%001_000 + if_c shl x,data + if_c andn x,_locks + if_c shr x,#3 + if_c shr t,#29 'ignore auto-repeat + if_c andn x,t wz + if_c xor _locks,x + if_c add data,#$DD + if_c_and_nz or stat,#4 'if change, set configure flag to update leds + + test y,#%11 wz 'get shift into nz + + if_nz cmp data,#$60+1 wc 'check shift1 + if_nz_and_c cmpsub data,#$5B wc + if_nz_and_c add data,#@shift1-@table + if_nz_and_c call #look + if_nz_and_c andn y,#%11 + + if_nz cmp data,#$3D+1 wc 'check shift2 + if_nz_and_c cmpsub data,#$27 wc + if_nz_and_c add data,#@shift2-@table + if_nz_and_c call #look + if_nz_and_c andn y,#%11 + + test _locks,#%010 wc 'check shift-alpha, considering capslock + muxnc :shift,#$20 + test _locks,#$40 wc + if_nz_and_nc xor :shift,#$20 + cmp data,#"z"+1 wc + if_c cmpsub data,#"a" wc +:shift if_c add data,#"A" + if_c andn y,#%11 + +:flags ror data,#8 'add shift/ctrl/alt/win flags + mov x,#4 '+$100 if shift +:loop test y,#%11 wz '+$200 if ctrl + shr y,#2 '+$400 if alt + if_nz or data,#1 '+$800 if win + ror data,#1 + djnz x,#:loop + rol data,#12 + + rdlong x,par 'if room in buffer and key valid, enter + sub x,#1 + and x,#$F + cmp x,_head wz + if_nz test data,#$FF wz + if_nz mov x,par + if_nz add x,#11*4 + if_nz add x,_head + if_nz add x,_head + if_nz wrword data,x + if_nz add _head,#1 + if_nz and _head,#$F + + test stat,#4 wc 'if not configure flag, done + if_nc jmp #update 'else configure to update leds +' +' +' Configure keyboard +' +configure mov data,#$F3 'set keyboard auto-repeat + call #transmit + mov data,_auto + and data,#%11_11111 + call #transmit + + mov data,#$ED 'set keyboard lock-leds + call #transmit + mov data,_locks + rev data,#-3 & $1F + test data,#%100 wc + rcl data,#1 + and data,#%111 + call #transmit + + mov x,_locks 'insert locks into _states + and x,#%111 + shl _states+7,#3 + or _states+7,x + ror _states+7,#3 + + mov _present,#1 'set _present + + jmp #update 'done +' +' +' Lookup byte in table +' +look ror data,#2 'perform lookup + movs :reg,data + add :reg,#table + shr data,#27 + mov x,data +:reg mov data,0 + shr data,x + + jmp #rand 'isolate byte +' +' +' Transmit byte to keyboard +' +transmit +_c1 or dira,cmask 'pull clock low + movs napshr,#13 'hold clock for ~128us (must be >100us) + call #nap +_d1 or dira,dmask 'pull data low + movs napshr,#18 'hold data for ~4us + call #nap +_c2 xor dira,cmask 'release clock + + test data,#$0FF wc 'append parity and stop bits to byte + muxnc data,#$100 + or data,dlsb + + mov x,#10 'ready 10 bits +transmit_bit call #wait_c0 'wait until clock low + shr data,#1 wc 'output data bit +_d2 muxnc dira,dmask + mov wcond,c1 'wait until clock high + call #wait + djnz x,#transmit_bit 'another bit? + + mov wcond,c0d0 'wait until clock and data low + call #wait + mov wcond,c1d1 'wait until clock and data high + call #wait + + call #receive_ack 'receive ack byte with timed wait + cmp data,#$FA wz 'if ack error, reset keyboard + if_nz jmp #reset + +transmit_ret ret +' +' +' Receive byte from keyboard +' +receive test _cpin,#$20 wc 'wait indefinitely for initial clock low + waitpne cmask,cmask +receive_ack + mov x,#11 'ready 11 bits +receive_bit call #wait_c0 'wait until clock low + movs napshr,#16 'pause ~16us + call #nap +_d3 test dmask,ina wc 'input data bit + rcr data,#1 + mov wcond,c1 'wait until clock high + call #wait + djnz x,#receive_bit 'another bit? + + shr data,#22 'align byte + test data,#$1FF wc 'if parity error, reset keyboard + if_nc jmp #reset +rand and data,#$FF 'isolate byte + +look_ret +receive_ack_ret +receive_ret ret +' +' +' Wait for clock/data to be in required state(s) +' +wait_c0 mov wcond,c0 '(wait until clock low) + +wait mov y,tenms 'set timeout to 10ms + +wloop movs napshr,#18 'nap ~4us + call #nap +_c3 test cmask,ina wc 'check required state(s) +_d4 test dmask,ina wz 'loop until got state(s) or timeout +wcond if_never djnz y,#wloop '(replaced with c0/c1/c0d0/c1d1) + + tjz y,#reset 'if timeout, reset keyboard +wait_ret +wait_c0_ret ret + + +c0 if_c djnz y,#wloop '(if_never replacements) +c1 if_nc djnz y,#wloop +c0d0 if_c_or_nz djnz y,#wloop +c1d1 if_nc_or_z djnz y,#wloop +' +' +' Nap +' +nap rdlong t,#0 'get clkfreq +napshr shr t,#18/16/13 'shr scales time + min t,#3 'ensure waitcnt won't snag + add t,cnt 'add cnt to time + waitcnt t,#0 'wait until time elapses (nap) + +nap_ret ret +' +' +' Initialized data +' +' +dlsb long 1 << 9 +tenms long 10_000 / 4 +' +' +' Lookup table +' ascii scan extkey regkey ()=keypad +' +table word $0000 '00 + word $00D8 '01 F9 + word $0000 '02 + word $00D4 '03 F5 + word $00D2 '04 F3 + word $00D0 '05 F1 + word $00D1 '06 F2 + word $00DB '07 F12 + word $0000 '08 + word $00D9 '09 F10 + word $00D7 '0A F8 + word $00D5 '0B F6 + word $00D3 '0C F4 + word $0009 '0D Tab + word $0060 '0E ` + word $0000 '0F + word $0000 '10 + word $F5F4 '11 Alt-R Alt-L + word $00F0 '12 Shift-L + word $0000 '13 + word $F3F2 '14 Ctrl-R Ctrl-L + word $0071 '15 q + word $0031 '16 1 + word $0000 '17 + word $0000 '18 + word $0000 '19 + word $007A '1A z + word $0073 '1B s + word $0061 '1C a + word $0077 '1D w + word $0032 '1E 2 + word $F600 '1F Win-L + word $0000 '20 + word $0063 '21 c + word $0078 '22 x + word $0064 '23 d + word $0065 '24 e + word $0034 '25 4 + word $0033 '26 3 + word $F700 '27 Win-R + word $0000 '28 + word $0020 '29 Space + word $0076 '2A v + word $0066 '2B f + word $0074 '2C t + word $0072 '2D r + word $0035 '2E 5 + word $CC00 '2F Apps + word $0000 '30 + word $006E '31 n + word $0062 '32 b + word $0068 '33 h + word $0067 '34 g + word $0079 '35 y + word $0036 '36 6 + word $CD00 '37 Power + word $0000 '38 + word $0000 '39 + word $006D '3A m + word $006A '3B j + word $0075 '3C u + word $0037 '3D 7 + word $0038 '3E 8 + word $CE00 '3F Sleep + word $0000 '40 + word $002C '41 , + word $006B '42 k + word $0069 '43 i + word $006F '44 o + word $0030 '45 0 + word $0039 '46 9 + word $0000 '47 + word $0000 '48 + word $002E '49 . + word $EF2F '4A (/) / + word $006C '4B l + word $003B '4C ; + word $0070 '4D p + word $002D '4E - + word $0000 '4F + word $0000 '50 + word $0000 '51 + word $0027 '52 ' + word $0000 '53 + word $005B '54 [ + word $003D '55 = + word $0000 '56 + word $0000 '57 + word $00DE '58 CapsLock + word $00F1 '59 Shift-R + word $EB0D '5A (Enter) Enter + word $005D '5B ] + word $0000 '5C + word $005C '5D \ + word $CF00 '5E WakeUp + word $0000 '5F + word $0000 '60 + word $0000 '61 + word $0000 '62 + word $0000 '63 + word $0000 '64 + word $0000 '65 + word $00C8 '66 BackSpace + word $0000 '67 + word $0000 '68 + word $C5E1 '69 End (1) + word $0000 '6A + word $C0E4 '6B Left (4) + word $C4E7 '6C Home (7) + word $0000 '6D + word $0000 '6E + word $0000 '6F + word $CAE0 '70 Insert (0) + word $C9EA '71 Delete (.) + word $C3E2 '72 Down (2) + word $00E5 '73 (5) + word $C1E6 '74 Right (6) + word $C2E8 '75 Up (8) + word $00CB '76 Esc + word $00DF '77 NumLock + word $00DA '78 F11 + word $00EC '79 (+) + word $C7E3 '7A PageDn (3) + word $00ED '7B (-) + word $DCEE '7C PrScr (*) + word $C6E9 '7D PageUp (9) + word $00DD '7E ScrLock + word $0000 '7F + word $0000 '80 + word $0000 '81 + word $0000 '82 + word $00D6 '83 F7 + +keypad1 byte $CA, $C5, $C3, $C7, $C0, 0, $C1, $C4, $C2, $C6, $C9, $0D, "+-*/" + +keypad2 byte "0123456789.", $0D, "+-*/" + +shift1 byte "{|}", 0, 0, "~" + +shift2 byte $22, 0, 0, 0, 0, "<_>?)!@#$%^&*(", 0, ":", 0, "+" +' +' +' Uninitialized data +' +dmask res 1 +cmask res 1 +stat res 1 +data res 1 +x res 1 +y res 1 +t res 1 + +_head res 1 'write-only +_present res 1 'write-only +_states res 8 'write-only +_dpin res 1 'read-only at start +_cpin res 1 'read-only at start +_locks res 1 'read-only at start +_auto res 1 'read-only at start + +'' +'' +'' _________ +'' Key Codes +'' +'' 00..DF = keypress and keystate +'' E0..FF = keystate only +'' +'' +'' 09 Tab +'' 0D Enter +'' 20 Space +'' 21 ! +'' 22 " +'' 23 # +'' 24 $ +'' 25 % +'' 26 & +'' 27 ' +'' 28 ( +'' 29 ) +'' 2A * +'' 2B + +'' 2C , +'' 2D - +'' 2E . +'' 2F / +'' 30 0..9 +'' 3A : +'' 3B ; +'' 3C < +'' 3D = +'' 3E > +'' 3F ? +'' 40 @ +'' 41..5A A..Z +'' 5B [ +'' 5C \ +'' 5D ] +'' 5E ^ +'' 5F _ +'' 60 ` +'' 61..7A a..z +'' 7B { +'' 7C | +'' 7D } +'' 7E ~ +'' +'' 80-BF (future international character support) +'' +'' C0 Left Arrow +'' C1 Right Arrow +'' C2 Up Arrow +'' C3 Down Arrow +'' C4 Home +'' C5 End +'' C6 Page Up +'' C7 Page Down +'' C8 Backspace +'' C9 Delete +'' CA Insert +'' CB Esc +'' CC Apps +'' CD Power +'' CE Sleep +'' CF Wakeup +'' +'' D0..DB F1..F12 +'' DC Print Screen +'' DD Scroll Lock +'' DE Caps Lock +'' DF Num Lock +'' +'' E0..E9 Keypad 0..9 +'' EA Keypad . +'' EB Keypad Enter +'' EC Keypad + +'' ED Keypad - +'' EE Keypad * +'' EF Keypad / +'' +'' F0 Left Shift +'' F1 Right Shift +'' F2 Left Ctrl +'' F3 Right Ctrl +'' F4 Left Alt +'' F5 Right Alt +'' F6 Left Win +'' F7 Right Win +'' +'' FD Scroll Lock State +'' FE Caps Lock State +'' FF Num Lock State +'' +'' +100 if Shift +'' +200 if Ctrl +'' +400 if Alt +'' +800 if Win +'' +'' eg. Ctrl-Alt-Delete = $6C9 +'' +'' +'' Note: Driver will buffer up to 15 keystrokes, then ignore overflow. + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/MenuItem.spin b/source/gui-demo/MenuItem.spin new file mode 100644 index 0000000..f71245d --- /dev/null +++ b/source/gui-demo/MenuItem.spin @@ -0,0 +1,125 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: MenuItem.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +''============================================================================ +'' MenuItem Control +''============================================================================ +'' +'' Creates a menu item. This is really like a text button, but when placed with +'' others and inside a simple box it can look like a menu bar. User determined +'' state information may be assigned to it. + + +VAR + word varGdx 'GUI control variable + long varScreenPtr 'screen buffer pointer + long varVgaPos 'starting position of the menu item + byte varTextN[18] 'normal text, 15 chars MAX, with room for terminating Null and bracketing spaces + byte varTextI[18] 'inverted text, 15 chars MAX, with room for terminating Null and bracketing spaces + byte varRow 'top row location + byte varCol 'left col location + byte varCol2 'right col location + byte varWidth 'width of text + byte varStatus '0=normal else user defined value + byte varVgaCols 'width of screen in columns + + +PUB Init( pRow, pCol, pTextPtr, pVgaPtr, pVgaWidth ) | strIdx + + varVgaCols := pVgaWidth + varRow := pRow + varCol := pCol + varScreenPtr := pVgaPtr + varStatus := 0 + varWidth := strsize( pTextPtr ) + 2 + varCol2 := varCol + varWidth - 1 + + varTextN[0] := 32 + bytemove( @varTextN[1], pTextPtr, varWidth - 2 ) 'copy menu item text string + varTextN[varWidth - 1] := 32 + varTextN[varWidth] := 0 + strIdx := 0 + repeat varWidth + varTextI[strIdx] := varTextN[strIdx]+128 'invert the string + strIdx++ + varTextI[strIdx] := 0 + + varVgaPos := varRow * varVgaCols + varCol 'now draw the menu item + bytemove( @byte[varScreenPtr][varVgaPos], @varTextI, varWidth ) + + +PUB DrawText( pMode ) + + if pMode & 1 + bytemove( @byte[varScreenPtr][varVgaPos], @varTextN, varWidth ) + else + bytemove( @byte[varScreenPtr][varVgaPos], @varTextI, varWidth ) + + +PUB IsIn( pCx, pCy ) : qq + + qq := false + + if ( pCx => varCol ) AND ( pCx =< varCol2 ) + if pCy == varRow + qq := true + + return qq + + +PUB SetText( pPtr ) | strIdx + + bytefill( @varTextN[1], 32, varWidth - 2 ) 'clear it first + bytemove( @varTextN[1], pPtr, strsize(pPtr) ) 'copy menu item text string + strIdx := 0 + repeat varWidth + varTextI[strIdx] := varTextN[strIdx]+128 'invert the string + strIdx++ + bytemove( @byte[varScreenPtr][varVgaPos], varTextI, varWidth ) + + +PUB SetStatus( pStat ) + varStatus := pStat 'user defined status value + + +Pub GetStatus + return varStatus + + +PUB set_gzidx( gzidx ) + varGdx := gzidx + + +PUB get_gzidx + return varGdx + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/Mouse.spin b/source/gui-demo/Mouse.spin new file mode 100644 index 0000000..fb7f470 --- /dev/null +++ b/source/gui-demo/Mouse.spin @@ -0,0 +1,492 @@ +''*************************************** +''* PS/2 Mouse Driver v1.1 * +''* Author: Chip Gracey * +''* Copyright (c) 2006 Parallax, Inc. * +''* See end of file for terms of use. * +''*************************************** + +' v1.0 - 01 May 2006 - original version +' v1.1 - 01 Jun 2006 - bound coordinates added to simplify upper objects + + +VAR + + long cog + + long oldx, oldy, oldz 'must be followed by parameters (10 contiguous longs) + + long par_x 'absolute x read-only (7 contiguous longs) + long par_y 'absolute y read-only + long par_z 'absolute z read-only + long par_buttons 'button states read-only + long par_present 'mouse present read-only + long par_dpin 'data pin write-only + long par_cpin 'clock pin write-only + + long bx_min, by_min, bz_min 'min/max must be contiguous + long bx_max, by_max, bz_max + long bx_div, by_div, bz_div + long bx_acc, by_acc, bz_acc + + +PUB start(dpin, cpin) : okay + +'' Start mouse driver - starts a cog +'' returns false if no cog available +'' +'' dpin = data signal on PS/2 jack +'' cpin = clock signal on PS/2 jack +'' +'' use 100-ohm resistors between pins and jack +'' use 10K-ohm resistors to pull jack-side signals to VDD +'' connect jack-power to 5V, jack-gnd to VSS + + stop + par_dpin := dpin + par_cpin := cpin + okay := cog := cognew(@entry, @par_x) + 1 + + +PUB stop + +'' Stop mouse driver - frees a cog + + if cog + cogstop(cog~ - 1) + longfill(@oldx, 0, 10) + + +PUB present : type + +'' Check if mouse present - valid ~2s after start +'' returns mouse type: +'' +'' 3 = five-button scrollwheel mouse +'' 2 = three-button scrollwheel mouse +'' 1 = two-button or three-button mouse +'' 0 = no mouse connected + + type := par_present + + +PUB button(b) : state + +'' Get the state of a particular button +'' returns t|f + + state := -(par_buttons >> b & 1) + + +PUB buttons : states + +'' Get the states of all buttons +'' returns buttons: +'' +'' bit4 = right-side button +'' bit3 = left-side button +'' bit2 = center/scrollwheel button +'' bit1 = right button +'' bit0 = left button + + states := par_buttons + + +PUB abs_x : x + +'' Get absolute-x + + x := par_x + + +PUB abs_y : y + +'' Get absolute-y + + y := par_y + + +PUB abs_z : z + +'' Get absolute-z (scrollwheel) + + z := par_z + + +PUB delta_reset + +'' Reset deltas + + oldx := par_x + oldy := par_y + oldz := par_z + + +PUB delta_x : x | newx + +'' Get delta-x + + newx := par_x + x := newx - oldx + oldx := newx + + +PUB delta_y : y | newy + +'' Get delta-y + + newy := par_y + y := newy - oldy + oldy := newy + + +PUB delta_z : z | newz + +'' Get delta-z (scrollwheel) + + newz := par_z + z := newz - oldz + oldz := newz + + +PUB bound_limits(xmin, ymin, zmin, xmax, ymax, zmax) | i + +'' Set bounding limits + + longmove(@bx_min, @xmin, 6) + + +PUB bound_scales(x_scale, y_scale, z_scale) + +'' Set bounding scales (usually +/-1's, bigger values divide) + + longmove(@bx_div, @x_scale, 3) + + +PUB bound_preset(x, y, z) | i, d + +'' Preset bound coordinates + + repeat i from 0 to 2 + d := ||bx_div[i] + bx_acc[i] := (x[i] - bx_min[i]) * d + d >> 1 + + +PUB bound_x : x + +'' Get bound-x + + x := bound(0, delta_x) + + +PUB bound_y : y + +'' Get bound-y + + y := bound(1, delta_y) + + +PUB bound_z : z + +'' Get bound-z + + z := bound(2, delta_z) + + +PRI bound(i, delta) : b | d + + d := bx_div[i] + b := bx_min[i] + (bx_acc[i] := bx_acc[i] + delta * (d < 0) | 1 #> 0 <# (bx_max[i] - bx_min[i] + 1) * ||d - 1) / ||d + + +DAT + +'*************************************** +'* Assembly language PS/2 mouse driver * +'*************************************** + + org +' +' +' Entry +' +entry mov p,par 'load input parameters: + add p,#5*4 '_dpin/_cpin + rdlong _dpin,p + add p,#4 + rdlong _cpin,p + + mov dmask,#1 'set pin masks + shl dmask,_dpin + mov cmask,#1 + shl cmask,_cpin + + test _dpin,#$20 wc 'modify port registers within code + muxc _d1,dlsb + muxc _d2,dlsb + muxc _d3,#1 + muxc _d4,#1 + test _cpin,#$20 wc + muxc _c1,dlsb + muxc _c2,dlsb + muxc _c3,#1 + + movd :par,#_x 'reset output parameters: + mov p,#5 '_x/_y/_z/_buttons/_present +:par mov 0,#0 + add :par,dlsb + djnz p,#:par +' +' +' Reset mouse +' +reset mov dira,#0 'reset directions + mov dirb,#0 + + mov stat,#1 'set reset flag +' +' +' Update parameters +' +update movd :par,#_x 'update output parameters: + mov p,par '_x/_y/_z/_buttons/_present + mov q,#5 +:par wrlong 0,p + add :par,dlsb + add p,#4 + djnz q,#:par + + test stat,#1 wc 'if reset flag, transmit reset command + if_c mov data,#$FF + if_c call #transmit +' +' +' Get data packet +' + mov stat,#0 'reset state + + call #receive 'receive first byte + + cmp data,#$AA wz 'powerup/reset? + if_z jmp #init + + mov _buttons,data 'data packet, save buttons + + call #receive 'receive second byte + + test _buttons,#$10 wc 'adjust _x + muxc data,signext + add _x,data + + call #receive 'receive third byte + + test _buttons,#$20 wc 'adjust _y + muxc data,signext + add _y,data + + and _buttons,#%111 'trim buttons + + cmp _present,#2 wc 'if not scrollwheel mouse, update parameters + if_c jmp #update + + + call #receive 'scrollwheel mouse, receive fourth byte + + cmp _present,#3 wz 'if 5-button mouse, handle two extra buttons + if_z test data,#$10 wc + if_z_and_c or _buttons,#%01000 + if_z test data,#$20 wc + if_z_and_c or _buttons,#%10000 + + shl data,#28 'adjust _z + sar data,#28 + sub _z,data + + jmp #update 'update parameters +' +' +' Initialize mouse +' +init call #receive '$AA received, receive id + + movs crate,#100 'try to enable 3-button scrollwheel type + call #checktype + movs crate,#200 'try to enable 5-button scrollwheel type + call #checktype + shr data,#1 'if neither, 3-button type + add data,#1 + mov _present,data + + movs srate,#200 'set 200 samples per second + call #setrate + + mov data,#$F4 'enable data reporting + call #transmit + + jmp #update +' +' +' Check mouse type +' +checktype movs srate,#200 'perform "knock" sequence to enable + call #setrate '..scrollwheel and extra buttons + +crate movs srate,#200/100 + call #setrate + + movs srate,#80 + call #setrate + + mov data,#$F2 'read type + call #transmit + call #receive + +checktype_ret ret +' +' +' Set sample rate +' +setrate mov data,#$F3 + call #transmit +srate mov data,#0 + call #transmit + +setrate_ret ret +' +' +' Transmit byte to mouse +' +transmit +_c1 or dira,cmask 'pull clock low + movs napshr,#13 'hold clock for ~128us (must be >100us) + call #nap +_d1 or dira,dmask 'pull data low + movs napshr,#18 'hold data for ~4us + call #nap +_c2 xor dira,cmask 'release clock + + test data,#$0FF wc 'append parity and stop bits to byte + muxnc data,#$100 + or data,dlsb + + mov p,#10 'ready 10 bits +transmit_bit call #wait_c0 'wait until clock low + shr data,#1 wc 'output data bit +_d2 muxnc dira,dmask + mov wcond,c1 'wait until clock high + call #wait + djnz p,#transmit_bit 'another bit? + + mov wcond,c0d0 'wait until clock and data low + call #wait + mov wcond,c1d1 'wait until clock and data high + call #wait + + call #receive_ack 'receive ack byte with timed wait + cmp data,#$FA wz 'if ack error, reset mouse + if_nz jmp #reset + +transmit_ret ret +' +' +' Receive byte from mouse +' +receive test _cpin,#$20 wc 'wait indefinitely for initial clock low + waitpne cmask,cmask +receive_ack + mov p,#11 'ready 11 bits +receive_bit call #wait_c0 'wait until clock low + movs napshr,#16 'pause ~16us + call #nap +_d3 test dmask,ina wc 'input data bit + rcr data,#1 + mov wcond,c1 'wait until clock high + call #wait + djnz p,#receive_bit 'another bit? + + shr data,#22 'align byte + test data,#$1FF wc 'if parity error, reset mouse + if_nc jmp #reset + and data,#$FF 'isolate byte + +receive_ack_ret +receive_ret ret +' +' +' Wait for clock/data to be in required state(s) +' +wait_c0 mov wcond,c0 '(wait until clock low) + +wait mov q,tenms 'set timeout to 10ms + +wloop movs napshr,#18 'nap ~4us + call #nap +_c3 test cmask,ina wc 'check required state(s) +_d4 test dmask,ina wz 'loop until got state(s) or timeout +wcond if_never djnz q,#wloop '(replaced with c0/c1/c0d0/c1d1) + + tjz q,#reset 'if timeout, reset mouse +wait_ret +wait_c0_ret ret + + +c0 if_c djnz q,#wloop '(if_never replacements) +c1 if_nc djnz q,#wloop +c0d0 if_c_or_nz djnz q,#wloop +c1d1 if_nc_or_z djnz q,#wloop +' +' +' Nap +' +nap rdlong t,#0 'get clkfreq +napshr shr t,#18/16/13 'shr scales time + min t,#3 'ensure waitcnt won't snag + add t,cnt 'add cnt to time + waitcnt t,#0 'wait until time elapses (nap) + +nap_ret ret +' +' +' Initialized data +' +dlsb long 1 << 9 +tenms long 10_000 / 4 +signext long $FFFFFF00 +' +' +' Uninitialized data +' +dmask res 1 +cmask res 1 +stat res 1 +data res 1 +p res 1 +q res 1 +t res 1 + +_x res 1 'write-only +_y res 1 'write-only +_z res 1 'write-only +_buttons res 1 'write-only +_present res 1 'write-only +_dpin res 1 'read-only +_cpin res 1 'read-only + + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/PushButton.spin b/source/gui-demo/PushButton.spin new file mode 100644 index 0000000..915e5b3 --- /dev/null +++ b/source/gui-demo/PushButton.spin @@ -0,0 +1,117 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: PushButton.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +''============================================================================ +'' Push Button Control +''============================================================================ +'' +'' Creates a straight forward pushbutton control. + + +OBJ + SBOX : "SimpleBox" + + +VAR + word varGdx 'GUI control variable + long varScreenPtr 'screen buffer pointer + long varVgaPos 'starting position of the menu item + byte varTextN[16] 'normal text, 15 chars MAX, with room for terminating Null + byte varTextI[16] 'inverted text, 15 chars MAX, with room for terminating Null + byte varRow 'top row location + byte varCol 'left col location + byte varCol2 'right col location + byte varWidth 'width of text + byte varVgaCols 'width of screen in columns + + +PUB Init( pRow, pCol, pTextPtr, pVgaPtr, pVgaWidth ) | strIdx + + varVgaCols := pVgaWidth + varRow := pRow + varCol := pCol + varScreenPtr := pVgaPtr + varWidth := strsize( pTextPtr )+ 2 + varCol2 := varCol + varWidth - 1 + + SBOX.DrawBox( pRow, pCol, varWidth, 3, 0, pVgaPtr, pVgaWidth ) + + bytemove( @varTextN[0], pTextPtr, varWidth - 2 ) 'copy menu item text string + + strIdx := 0 + repeat varWidth-2 + varTextI[strIdx] := varTextN[strIdx]+128 'invert the string + strIdx++ + + varVgaPos := varRow * varVgaCols + varCol + varVgaCols + 1 + bytemove( @byte[varScreenPtr][varVgaPos], varTextI, varWidth - 2 ) + + +PUB DrawText( pMode ) + + if pMode & 1 + bytemove( @byte[varScreenPtr][varVgaPos], @varTextI, varWidth-2 ) + else + bytemove( @byte[varScreenPtr][varVgaPos], @varTextN, varWidth-2 ) + + +PUB IsIn( pCx, pCy ) : qq + + qq := false + + if ( pCx > varCol ) AND ( pCx < varCol2 ) + if pCy == varRow+1 + qq := true + + return qq + + +PUB SetText( pPtr ) | strIdx + + bytefill( @varTextN[0], 32, varWidth - 2 ) 'clear it first + bytemove( @varTextN[0], pPtr, strsize(pPtr) ) 'copy menu item text string + + strIdx := 0 + repeat varWidth-2 + varTextI[strIdx] := varTextN[strIdx]+128 'invert the string + strIdx++ + bytemove( @byte[varScreenPtr][varVgaPos], varTextN, varWidth-2 ) + + +PUB set_gzidx( gzidx ) + varGdx := gzidx + + +PUB get_gzidx + return varGdx + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/RadioCheck.spin b/source/gui-demo/RadioCheck.spin new file mode 100644 index 0000000..89f1b5d --- /dev/null +++ b/source/gui-demo/RadioCheck.spin @@ -0,0 +1,153 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: RadioCheck.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +''============================================================================ +'' Button Control +''============================================================================ +'' +'' Creates Radio Buttons or Check Boxes +'' + +VAR + word varGdx 'GUI control variable + long varScreenPtr 'screen buffer pointer + long varVgaPos 'start location of the button + byte varTextN[16] 'normal text, 15 chars MAX, with room for terminating Null + byte varTextI[16] 'inverted text, 15 chars MAX, with room for terminating Null + byte varRow 'top row location + byte varCol 'left col location + byte varCol2 'right col location + byte varWidth 'width of text + byte varStatus 'status byte 0 = none 1 = active + byte varSelChar 'selected character + byte varUnselChar 'unselected character + byte varVgaCols 'width of screen in columns + + +PUB Init( pRow, pCol, pTextWidth, pStyle, pTextPtr, pVgaPtr, pVgaWidth ) | strIdx, vgaIdx + + varVgaCols := pVgaWidth + varStatus := 0 + varRow := pRow + varCol := pCol + varWidth := pTextWidth + varScreenPtr := pVgaPtr + varVgaPos := varRow * varVgaCols + varCol + varCol2 := varCol + varWidth + 1 + + if pStyle == 0 + varSelChar := 7 'CheckBox Style + varUnselChar := 6 + else + varSelChar := 5 'Radio Button Style + varUnselChar := 4 + + strIdx := strsize( pTextPtr ) + bytemove( @varTextN, pTextPtr, strIdx ) 'copy checkbox text string + bytefill(@varTextN[strIdx],32,pTextWidth-strIdx) 'pad out with spaces + varTextN[pTextWidth] := 0 + strIdx := 0 + repeat pTextWidth + varTextI[strIdx] := varTextN[strIdx]+128 'create inverted string + strIdx++ + varTextI[strIdx] := 0 + + vgaIdx := varVgaPos 'now draw the checkbox + + byte[varScreenPtr][vgaIdx++] := varUnselChar 'empty bullet + byte[varScreenPtr][vgaIdx++] := 32 + + strIdx := strsize( @varTextN ) + bytemove( @byte[varScreenPtr][vgaIdx], @varTextN, strIdx ) + + +PUB DrawText( pMode ) | strIdx, vgaIdx + + strIdx := strsize( @varTextN ) + vgaIdx := varVgaPos 'bullet location + + if varStatus == 1 + byte[varScreenPtr][vgaIdx] := varSelChar 'selected bullet + else + byte[varScreenPtr][vgaIdx] := varUnselChar 'non-selected bullet + + vgaIdx += 2 'checkbox text location + + if pMode & 1 + bytemove( @byte[varScreenPtr][vgaIdx], @varTextI, strIdx ) + else + bytemove( @byte[varScreenPtr][vgaIdx], @varTextN, strIdx ) + + + +PUB IsIn( pCx, pCy ) | retVal + + retVal := false + + if ( pCx => varCol ) AND ( pCx =< varCol2 ) + if pCy == varRow + retVal := true + + return retVal + + +PUB Select( pSel ) + + if pSel <> -1 + varStatus := pSel + else + if varStatus == 0 + varStatus := 1 + else + varStatus := 0 + + if varStatus == 1 + byte[varScreenPtr][varVgaPos] := varSelChar 'selected bullet + else + byte[varScreenPtr][varVgaPos] := varUnselChar 'non-selected + + +PUB IsSet + if varStatus == 1 + return true + else + return false + + +PUB set_gzidx( gzidx ) + varGdx := gzidx + + +PUB get_gzidx + return varGdx + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/SimpleBox.spin b/source/gui-demo/SimpleBox.spin new file mode 100644 index 0000000..3370a95 --- /dev/null +++ b/source/gui-demo/SimpleBox.spin @@ -0,0 +1,93 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: SimpleBox.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +''============================================================================ +'' SimpleBox Control +''============================================================================ +'' +'' Just draws a box with optional title, plain and simple. +'' + +PUB DrawBox( pRow, pCol, pWidth, pHeight, pTitlePtr, pVgaPtr, pVgaWidth ) | idx, vgaIdx, rowCnt, tbTitle, vgaStartIdx + vgaStartIdx := pRow * pVgaWidth + pCol + + vgaIdx := vgaStartIdx 'clear the area first + repeat pHeight + bytefill(@byte[pVgaPtr][vgaIdx],32,pWidth) + vgaIdx += pVgaWidth + + vgaIdx := vgaStartIdx 'goto top left row/col + + byte[pVgaPtr][vgaIdx++] := 10 'top left corner char + bytefill(@byte[pVgaPtr][vgaIdx],14,pWidth-2) 'horizontal line + vgaIdx += pWidth - 2 + byte[pVgaPtr][vgaIdx++] := 11 'top right corner char + + vgaIdx := vgaStartIdx + pVgaWidth 'move down to start of next row + + if pTitlePtr <> 0 'if there is a title + + byte[pVgaPtr][vgaIdx++] := 15 'vertical line char + + idx := strsize( pTitlePtr ) + bytemove( @byte[pVgaPtr][vgaIdx], pTitlePtr, idx )'place title + vgaIdx += pWidth - 2 + byte[pVgaPtr][vgaIdx++] := 15 'vertical line char + + vgaIdx := vgaStartIdx + 2 * pVgaWidth 'move down to start of next row + + byte[pVgaPtr][vgaIdx++] := 18 'left 'tee' char + bytefill(@byte[pVgaPtr][vgaIdx],14,pWidth-2)'horizontal line + vgaIdx += pWidth - 2 + byte[pVgaPtr][vgaIdx++] := 19 'right 'tee' char + + rowCnt := 3 'row counter + + else + + rowCnt := 1 'row counter + + vgaIdx := vgaStartIdx + pVgaWidth * rowCnt 'move down to start of next row + repeat pHeight - rowCnt - 1 + byte[pVgaPtr][vgaIdx++] := 15 'vertical line char + vgaIdx += pWidth - 2 + byte[pVgaPtr][vgaIdx++] := 15 'vertical line char + vgaIdx -= pWidth + vgaIdx += pVgaWidth + + 'the above left vgaIdx pointing to the start of the last line + + byte[pVgaPtr][vgaIdx++] := 12 'bottom left corner char + bytefill(@byte[pVgaPtr][vgaIdx],14,pWidth-2) 'horizontal line + vgaIdx += pWidth - 2 + byte[pVgaPtr][vgaIdx++] := 13 'bottom right corner char + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/Simple_Numbers.spin b/source/gui-demo/Simple_Numbers.spin new file mode 100644 index 0000000..ef3c13f --- /dev/null +++ b/source/gui-demo/Simple_Numbers.spin @@ -0,0 +1,197 @@ +''**************************************** +''* Simple_Numbers * +''* Authors: Chip Gracey, Jon Williams * +''* Copyright (c) 2006 Parallax, Inc. * +''* See end of file for terms of use. * +''**************************************** +'' +'' Provides simple numeric conversion methods; all methods return a pointer to +'' a string. +'' +'' Updated... 29 APR 2006 + + +CON + + MAX_LEN = 64 ' 63 chars + zero terminator + + +VAR + + long idx ' pointer into string + byte nstr[MAX_LEN] ' string for numeric data + + +PUB dec(value) + +'' Returns pointer to signed-decimal string + + clrstr(@nstr, MAX_LEN) ' clear output string + return decstr(value) ' return pointer to numeric string + + +PUB decf(value, width) | t_val, field + +'' Returns pointer to signed-decimal, fixed-width (space padded) string + + clrstr(@nstr, MAX_LEN) + width := 1 #> width <# constant(MAX_LEN - 1) ' qualify field width + + t_val := ||value ' work with absolute + field~ ' clear field + + repeat while t_val > 0 ' count number of digits + field++ + t_val /= 10 + + field #>= 1 ' min field width is 1 + if value < 0 ' if value is negative + field++ ' bump field for neg sign indicator + + if field < width ' need padding? + repeat (width - field) ' yes + nstr[idx++] := " " ' pad with space(s) + + return decstr(value) + + +PUB decx(value, digits) | div + +'' Returns pointer to zero-padded, signed-decimal string +'' -- if value is negative, field width is digits+1 + + clrstr(@nstr, MAX_LEN) + digits := 1 #> digits <# 10 + + if (value < 0) ' negative value? + -value ' yes, make positive + nstr[idx++] := "-" ' and print sign indicator + + div := 1_000_000_000 ' initialize divisor + if digits < 10 ' less than 10 digits? + repeat (10 - digits) ' yes, adjust divisor + div /= 10 + + value //= (div * 10) ' truncate unused digits + + repeat digits + nstr[idx++] := (value / div + "0") ' convert digit to ASCII + value //= div ' update value + div /= 10 ' update divisor + + return @nstr + + +PUB hex(value, digits) + +'' Returns pointer to a digits-wide hexadecimal string + + clrstr(@nstr, MAX_LEN) + return hexstr(value, digits) + + +PUB ihex(value, digits) + +'' Returns pointer to a digits-wide, indicated (with $) hexadecimal string + + clrstr(@nstr, MAX_LEN) + nstr[idx++] := "$" + return hexstr(value, digits) + + +PUB bin(value, digits) + +'' Returns pointer to a digits-wide binary string + + clrstr(@nstr, MAX_LEN) + return binstr(value, digits) + + +PUB ibin(value, digits) + +'' Returns pointer to a digits-wide, indicated (with %) binary string + + clrstr(@nstr, MAX_LEN) + nstr[idx++] := "%" ' preface with binary indicator + return binstr(value, digits) + + +PRI clrstr(strAddr, size) + +' Clears string at strAddr +' -- also resets global character pointer (idx) + + bytefill(strAddr, 0, size) ' clear string to zeros + idx~ ' reset index + + +PRI decstr(value) | div, z_pad + +' Converts value to signed-decimal string equivalent +' -- characters written to current position of idx +' -- returns pointer to nstr + + if (value < 0) ' negative value? + -value ' yes, make positive + nstr[idx++] := "-" ' and print sign indicator + + div := 1_000_000_000 ' initialize divisor + z_pad~ ' clear zero-pad flag + + repeat 10 + if (value => div) ' printable character? + nstr[idx++] := (value / div + "0") ' yes, print ASCII digit + value //= div ' update value + z_pad~~ ' set zflag + elseif z_pad or (div == 1) ' printing or last column? + nstr[idx++] := "0" + div /= 10 + + return @nstr + + +PRI hexstr(value, digits) + +' Converts value to digits-wide hexadecimal string equivalent +' -- characters written to current position of idx +' -- returns pointer to nstr + + digits := 1 #> digits <# 8 ' qualify digits + value <<= (8 - digits) << 2 ' prep most significant digit + repeat digits + nstr[idx++] := lookupz((value <-= 4) & $F : "0".."9", "A".."F") + + return @nstr + + +PRI binstr(value, digits) + +' Converts value to digits-wide binary string equivalent +' -- characters written to current position of idx +' -- returns pointer to nstr + + digits := 1 #> digits <# 32 ' qualify digits + value <<= 32 - digits ' prep MSB + repeat digits + nstr[idx++] := (value <-= 1) & 1 + "0" ' move digits (ASCII) to string + + return @nstr + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/SpinBox.spin b/source/gui-demo/SpinBox.spin new file mode 100644 index 0000000..183e444 --- /dev/null +++ b/source/gui-demo/SpinBox.spin @@ -0,0 +1,225 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: SpinBox.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +''============================================================================ +'' Simple SpinBox +''============================================================================ +'' +'' Creates a simple spin box control. Data may be text or numeric. + + +CON + MAX_LEN = 16 + + +OBJ + SBOX : "SimpleBox" + + +VAR + word varGdx 'GUI control variable + long varScreenPtr 'screen buffer pointer + long varDataPtr 'points to the display data (not the setup bytes) + long varDrawIdx 'vga index to start of display item area + long n_idx 'index into number string + word varUpIdx 'vga index of up arrow + word varDnIdx 'vga index of down arrow + byte n_str[MAX_LEN] 'string for numeric data + byte varRow 'top row location + byte varCol 'left col location + byte varCol2 'right col location + byte varWidth 'width ... info area is 6 less than total width + byte varVgaCols 'width of screen in columns + byte varNumData 'number of data items + byte varDataIdx 'current data item displayed + byte varType '0 = text 1 = numeric + + +PUB Init ( pRow, pCol, pWidth, pType, pNum, pDataPtr, pVgaPtr, pVgaWidth ) | vgaIdx + + varVgaCols := pVgaWidth + varRow := pRow + varCol := pCol + varWidth := pWidth + varScreenPtr := pVgaPtr + varCol2 := varCol + varWidth + varDataPtr := pDataPtr + varType := pType + varNumData := pNum + varDataIdx := 0 + varDrawIdx := varRow*varVgaCols+varVgaCols+varCol+1 'display item location + + SBOX.DrawBox( pRow, pCol, pWidth, 3, 0, pVgaPtr, pVgaWidth ) + + vgaIdx := varRow * varVgaCols + varCol + varWidth - 3 + byte[varScreenPtr][vgaIdx] := 16 'top 'tee' char + vgaIdx += varVgaCols + byte[varScreenPtr][vgaIdx] := 15 'vertical line char + varDnIdx := vgaIdx+1 'save position of DN arrow + byte[varScreenPtr][vgaIdx+1] := 3 'down arrow char + vgaIdx += varVgaCols + byte[varScreenPtr][vgaIdx] := 17 'bottom 'tee' char + + vgaIdx := varRow * varVgaCols + varCol + varWidth - 5 + byte[varScreenPtr][vgaIdx] := 16 'top 'tee' char + vgaIdx += varVgaCols + byte[varScreenPtr][vgaIdx] := 15 'vertical line char + varUpIdx := vgaIdx+1 'save position of UP arrow + byte[varScreenPtr][vgaIdx+1] := 2 'up arrow char + vgaIdx += varVgaCols + byte[varScreenPtr][vgaIdx] := 17 'bottom 'tee' char + + DrawData( varDataIdx ) + + +PUB IsIn( pCx, pCy ) | retVal + + retVal := false + + if ( pCx => varCol ) AND ( pCx =< varCol2 ) + if pCy == varRow + 1 + retVal := true + + return retVal + + +PUB Clicked( pCx, pCy ) | idx, retVal + + retVal := -1 'default return if neither arrow was pressed or at boundary + + idx := pCy*varVgaCols+pCx + + if idx == varUpIdx + if varDataIdx <> varNumData - 1 + varDataIdx++ + retVal := varDataIdx + + if idx == varDnIdx + if varDataIdx <> 0 + varDataIdx-- + retVal := varDataIdx + + if retVal <> -1 + DrawData( varDataIdx ) + + return retVal + + +PUB GetDataIndex +'returns the zero based index of the currently displaying data + return varDataIdx + + +PUB set_gzidx( gzidx ) + varGdx := gzidx + + +PUB get_gzidx + return varGdx + + +PRI DrawData( didx ) | tptr, strLen +'Draws the specified (by zero based index) data in the spin box display area. +' didx = index of data item to display + + tptr := varDataPtr + bytefill(@byte[varScreenPtr][varDrawIdx],32,varWidth-6) + + if varType == 0 '--------------- + + strLen := strsize( tptr ) + repeat didx + tptr += strLen + 1 + strLen := strsize( tptr ) + bytemove(@byte[varScreenPtr][varDrawIdx], tptr, strLen ) + + else '------------ + strLen := varWidth-6 + strLen := 1 #> strLen <# constant(MAX_LEN - 1) + bytemove(@byte[varScreenPtr][varDrawIdx], decf(long[tptr][didx],strLen), strLen ) + + +''============================================================================= +'' The routine that follows is taken from the Simple_Numbers.spin object. +'' However, I collapsed clrstr() and decstr() into this decf() function. +'' +''**************************************** +''* Simple_Numbers * +''* Authors: Chip Gracey, Jon Williams * +''* Copyright (c) 2006 Parallax, Inc. * +''* See end of file for terms of use. * +''**************************************** + +''============================================================================= +PRI decf(value, width) | t_val, field, div, z_pad + +'' Converts value to signed-decimal string equivalent +'' - characters written to current position of n_idx +'' - returns pointer to n_str: signed-decimal, fixed-width, space padded string + + n_idx~ ' reset index + t_val := ||value ' work with absolute + field~ ' clear field + + bytefill(@n_str, 0, MAX_LEN) ' clear string to zeros + + repeat while t_val > 0 ' count number of digits + field++ + t_val /= 10 + + field #>= 1 ' min field width is 1 + if value < 0 ' if value is negative + field++ ' - bump field for neg sign indicator + + if field < width ' need padding? + repeat (width - field) ' yes + n_str[n_idx++] := " " ' - pad with space(s) + + if (value < 0) ' negative value? + -value ' - yes, make positive + n_str[n_idx++] := "-" ' - and print sign indicator + + div := 1_000_000_000 ' initialize divisor + z_pad~ ' clear zero-pad flag + + repeat 10 + if (value => div) ' printable character? + n_str[n_idx++] := (value / div + "0") ' - yes, print ASCII digit + value //= div ' - update value + z_pad~~ ' - set zflag + elseif z_pad or (div == 1) ' printing or last column? + n_str[n_idx++] := "0" + div /= 10 + + return @n_str + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/StatusLamp.spin b/source/gui-demo/StatusLamp.spin new file mode 100644 index 0000000..a8bcad9 --- /dev/null +++ b/source/gui-demo/StatusLamp.spin @@ -0,0 +1,115 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: StatusLamp.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +''============================================================================ +'' Status Lamp +''============================================================================ +'' +'' Creates status lamp to provide visual feedback of conditions. +'' +'' You create this item with the Init() function then you must set a status +'' right away, on or off (or else it will not show anything). + + +VAR + word varGdx 'GUI control variable + long varVgaPos 'screen location of start of input area + long varScreenPtr 'screen buffer pointer + long varCxPtr 'points to the text cursor x position variable + byte varRow 'top row location + byte varCol 'left col location + byte varCol2 'right col location + byte varWidth 'width ... text width is 2 less than total width + byte varTitleWidth 'number of rows used for title area ( 0 or 2 ) + byte varStatus '0 = off 1 = on + byte varVgaCols 'width of screen in columns + + +PUB Init ( pRow, pCol, pWidth, pTitlePtr, pVgaPtr, pVgaWidth ) | vgaIdx + + varVgaCols := pVgaWidth + varRow := pRow + varCol := pCol + varWidth := pWidth + varTitleWidth := strsize( pTitlePtr ) + varScreenPtr := pVgaPtr + varCol2 := varCol + varWidth + + vgaIdx := varRow * varVgaCols + varCol + bytefill( @byte[varScreenPtr][vgaIdx], 32, varWidth ) + bytemove( @byte[varScreenPtr][vgaIdx], pTitlePtr, varTitleWidth ) + + varVgaPos := varRow*varVgaCols+varCol+varWidth-4 'save status text area start + byte[varScreenPtr][varVgaPos-2] := ":" + + +PUB IsIn( pCx, pCy ) : qq + + qq := false + + if ( pCx => varCol ) AND ( pCx =< varCol2 ) + if pCy == varRow + qq := true + + return qq + + +PUB Set( pSet, pStr ) | strLen + + varStatus := pSet + + strLen := strsize( pStr ) + strLen := 1 #> strLen <# 4 + + bytefill( @byte[varScreenPtr][varVgaPos], 32, 4 ) + bytemove( @byte[varScreenPtr][varVgaPos], pStr, strLen ) + + if varStatus == 1 + byte[varScreenPtr][varVgaPos+0] += 128 + byte[varScreenPtr][varVgaPos+1] += 128 + byte[varScreenPtr][varVgaPos+2] += 128 + byte[varScreenPtr][varVgaPos+3] += 128 + + +PUB GetStatus + return varStatus + + + +PUB set_gzidx( gzidx ) + varGdx := gzidx + + +PUB get_gzidx + return varGdx + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/TextBox.spin b/source/gui-demo/TextBox.spin new file mode 100644 index 0000000..9c24d69 --- /dev/null +++ b/source/gui-demo/TextBox.spin @@ -0,0 +1,195 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' File: TextBox.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +''============================================================================ +'' TextBox Control +''============================================================================ +'' +'' Creates a simple text box with auto scrolling text area +'' +'' This control is a text window that you can print ASCII strings to. You can +'' set it to truncate ot wrap long lines. If lines are wrapped all wrapped +'' lines will be prefixed with an inverted right arrow character to mark the +'' wrapping operation. Leading and trailing CRLF characters are stripped from +'' the string but CRLFs inside the string remain and will be print as "funny" +'' characters. A titlebar with a caption may optionally be applied. + +OBJ + SBOX : "SimpleBox" + + +VAR + word varGdx 'GUI control variable + long varScreenPtr 'screen buffer pointer + byte varRow 'top row location + byte varRow2 'bottom row location + byte varCol 'left col location + byte varCol2 'right col location + byte varWidth 'width ... text width is 2 less than total width + byte varHeight 'height ... text height is 2 or 4 less than total height + byte varTitle 'number of rows used for title area ( 0 or 2 ) + byte varRowIdx 'index to current row to be written + byte varVgaCols 'width of screen in columns + byte varWrap '0=truncate lines 1=wrap lines (marks wrapped lines) + + +PUB Init( pRow, pCol, pWidth, pHeight, pWrap, pTitlePtr, pVgaPtr, pVgaWidth ) + + varVgaCols := pVgaWidth + varRow := pRow + varCol := pCol + varWidth := pWidth + varHeight := pHeight + varWrap := pWrap + varRow2 := pRow + 2 + varCol2 := pCol + pWidth - 1 + varRowIdx := 0 + varScreenPtr := pVgaPtr + + if pTitlePtr == 0 'no title text ? + varTitle := 0 + else + varTitle := 2 + + SBOX.DrawBox( pRow, pCol, pWidth, pHeight, pTitlePtr, pVgaPtr, pVgaWidth ) + + +PUB IsIn( pCx, pCy ) : qq + + qq := false + + if ( pCx => varCol ) AND ( pCx =< varCol2 ) + if ( pCy => ( varRow + varTitle ) ) AND ( pCy =< varRow2 ) + qq := true + + return qq + + +PUB Clear | tbRows, idx, vgaIdx + + tbRows := varHeight - varTitle - 2 + + vgaIdx := ( varRow + varTitle + 1 ) * varVgaCols + varCol + 1 + + repeat tbRows + bytefill( @byte[varScreenPtr][vgaIdx], 32, varWidth - 2 ) + vgaIdx += varVgaCols + + varRowIdx := 0 + + +PUB Print( pTxtPtr, pSize ) | strLen, tbRows, vgaIdx + + tbRows := varHeight - varTitle - 2 + if varRowIdx == tbRows 'if full, scroll up + Scroll + + vgaIdx := (varRow+varTitle+varRowIdx+1)*varVgaCols+varCol+1 'index to screen + + if pSize <> 0 'determine string size + strLen := pSize + else + strLen := strsize( pTxtPtr ) + + if strlen > 0 'strip leading CRLF + repeat while byte[pTxtPtr][0] < 32 + strLen-- + pTxtPtr++ + if strLen == 0 + quit + + if strLen > 0 'strip trailing CRLF + repeat while byte[pTxtPtr][strLen-1] < 32 + strLen-- + if strLen == 0 + quit + + if varWrap == 0 'if not wrapping lines + strLen <#= (varWidth-2) ' - truncate line length to window width + + if strLen =< varWidth-2 + bytemove(@byte[varScreenPtr][vgaIdx],pTxtPtr,strLen)' - copy whole string + if varRowIdx < tbRows + varRowIdx++ + else + bytemove(@byte[varScreenPtr][vgaIdx],pTxtPtr,varWidth-2)' - copy part string + if varRowIdx < tbRows + varRowIdx++ + strlen -= varWidth-2 + pTxtPtr += varWidth-2 + + repeat 'repeat till all of string done + if varRowIdx == tbRows 'scroll if required + Scroll + vgaIdx := (varRow+varTitle+varRowIdx+1)*varVgaCols+varCol+1 'index to screen + byte[varScreenPtr][vgaIdx] := $81 'inverted right arrow to show wrap + if strLen =< varWidth-3 + bytemove(@byte[varScreenPtr][vgaIdx+1],pTxtPtr,strLen)' - copy remaining string + if varRowIdx < tbRows + varRowIdx++ + quit + else + bytemove(@byte[varScreenPtr][vgaIdx+1],pTxtPtr,varWidth-3)' copy part string + strlen -= varWidth-3 + pTxtPtr += varWidth-3 + if varRowIdx < tbRows + varRowIdx++ + + +PUB Scroll | vgaIdx, tbRows + + tbRows := varHeight - varTitle - 2 + vgaIdx := ( varRow + varTitle + 1 ) * varVgaCols + varCol + repeat tbRows - 1 + longmove( @byte[varScreenPtr][vgaIdx], @byte[varScreenPtr][vgaIdx+varVgaCols], varWidth / 4 ) + vgaIdx += varVgaCols + bytefill( @byte[varScreenPtr][vgaIdx+1], 32, varWidth - 2 ) + varRowIdx-- + + +PUB Title( pTxtPtr ) | strIdx, vgaIdx + + if varTitle <> 0 + strIdx := strSize( pTxtPtr ) + vgaIdx := varRow * varVgaCols + varCol + varVgaCols +1 'title location + bytefill( @byte[varScreenPtr][vgaIdx], 32, varWidth - 2 ) + bytemove( @byte[varScreenPtr][vgaIdx], pTxtPtr, strIdx ) + + +PUB set_gzidx( gzidx ) + varGdx := gzidx + + +PUB get_gzidx + return varGdx + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/Timer.spin b/source/gui-demo/Timer.spin new file mode 100644 index 0000000..7be4a59 --- /dev/null +++ b/source/gui-demo/Timer.spin @@ -0,0 +1,128 @@ +'' =========================================================================== +'' VGA High-Res Text UI Elements Base UI Support Functions v1.2 +'' +'' FILE: Timer.spin +'' Author: Allen Marincak +'' Copyright (c) 2009 Allen MArincak +'' See end of file for terms of use +'' =========================================================================== +'' +'' ============================================================================ +'' Timer function +'' ============================================================================ +'' +'' Starts a new cog to provide timing functionality. +'' +'' There are 8 timers available, the code running on the new cog simply +'' decrements each timer value at the rate specified in the start() call. +'' +'' Only the first object to create this needs to call the START method. That +'' will launch it on a new COG, other objects can reference it in the OBJ +'' section but do not need to start it, just call the public methods. +'' ============================================================================ + + +DAT +' stack size determined StackLengthAJM.spin + cog long 0 'cog execute is running on + stack long 0,0,0,0,0,0,0,0,0,0,0,0 'stack space 12 longs + tmrs_used byte 0,0,0,0,0,0,0,0 'bitfield signifying timers in use + timers word 0,0,0,0,0,0,0,0 'timer values (16 bit) + + +PUB start( period ) : okay1 +'' +'' Launches TIMER TASK on new cog, returns 0 on error, else the cog that was +'' started up. +'' - period is the fractional part of a second to operate at +'' example: 10 = 1/10th of a second +'' 30 = 1/30th of a second +'' 100 = 1/100th of a second + + wordfill( @timers, 0, 8 ) + bytefill( @tmrs_used, 0, 8 ) + + cog := cognew( execute( period, @timers ), @stack ) + 1 + okay1 := cog + + +PUB register : new_tmr | idx +'' Register a timer. Returns the first free timer (8 timers numbered 0 to 7) +'' or returns -1 if none are available. + + repeat idx from 0 to 7 + if tmrs_used[idx] == 0 + tmrs_used[idx] := 1 + new_tmr := idx + return + + new_tmr := -1 + + +PUB unregister( tmrid ) +'' Unregisters a timer, frees it up for reuse. + + if tmrs_used[tmrid] == 1 + timers[tmrid] := 0 + tmrs_used[tmrid] := 0 + + +PUB set( tmrid, val ) +'' Sets a registered timer with a 16 bit value. + + if tmrs_used[tmrid] == 1 + timers[tmrid] := val + + +PUB isClr( tmrid ): clr +'' Checks the status of the registered timer. +'' returns 1 if it has expired (zeroed) +'' 0 if is still running + + clr := 0 + if timers[tmrid] == 0 + clr := 1 + + +PUB read( tmrid ) +'' returns the current count of a registered timer. + + return timers[tmrid] + + +PRI execute( period, ptr_tmrs ) | idx, interval_cnt, time_base +'' new cog executes this, it just decrements the timers + + interval_cnt := clkfreq / period + time_base := cnt + + repeat + waitcnt( time_base += interval_cnt ) + repeat idx from 0 to 7 + if word[ptr_tmrs][idx] <> 0 + word[ptr_tmrs][idx] -= 1 + + +{{ +┌────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy│ +│of this software and associated documentation files (the "Software"), to │ +│deal in the Software without restriction, including without limitation the │ +│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │ +│sell copies of the Software, and to permit persons to whom the Software is │ +│furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in │ +│all copies or substantial portions of the Software. │ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │ +│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │ +│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │ +│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │ +│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │ +│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│ +│IN THE SOFTWARE. │ +└────────────────────────────────────────────────────────────────────────────┘ +}} \ No newline at end of file diff --git a/source/gui-demo/VGA_HiRes_Text.spin b/source/gui-demo/VGA_HiRes_Text.spin new file mode 100644 index 0000000..e3f19d8 --- /dev/null +++ b/source/gui-demo/VGA_HiRes_Text.spin @@ -0,0 +1,542 @@ +''*************************************** +''* VGA High-Res Text Driver v1.0 * +''* Author: Chip Gracey * +''* Copyright (c) 2006 Parallax, Inc. * +''* See end of file for terms of use. * +''*************************************** +'' +'' This object generates a 1024x768 VGA signal which contains 128 columns x 64 +'' rows of 8x12 characters. Each row can have a unique forground/background +'' color combination and each character can be inversed. There are also two +'' cursors which can be independently controlled (ie. mouse and keyboard). A +'' sync indicator signals each time the screen is refreshed (you may ignore). +'' +'' You must provide buffers for the screen, colors, cursors, and sync. Once +'' started, all interfacing is done via memory. To this object, all buffers are +'' read-only, with the exception of the sync indicator which gets written with +'' -1. You may freely write all buffers to affect screen appearance. Have fun! +'' + +CON + +'{' 1024 x 768 @ 57Hz settings: 128 x 64 characters + + hp = 1024 'horizontal pixels + vp = 768 'vertical pixels + hf = 16 'horizontal front porch pixels + hs = 96 'horizontal sync pixels + hb = 176 'horizontal back porch pixels + vf = 1 '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 = 60 'pixel rate in MHz at 80MHz system clock (5MHz granularity) +'} + +{' 800 x 600 @ 75Hz settings: 100 x 50 characters + + hp = 800 'horizontal pixels + vp = 600 'vertical pixels + hf = 40 'horizontal front porch pixels + hs = 128 'horizontal sync pixels + hb = 88 'horizontal back porch pixels + vf = 1 'vertical front porch lines + vs = 4 'vertical sync lines + vb = 23 'vertical back porch lines + hn = 0 'horizontal normal sync state (0|1) + vn = 0 'vertical normal sync state (0|1) + pr = 50 'pixel rate in MHz at 80MHz system clock (5MHz granularity) +} + +{' 640 x 480 @ 69Hz settings: 80 x 40 characters + + hp = 640 'horizontal pixels + vp = 480 '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 = 30 'pixel rate in MHz at 80MHz system clock (5MHz granularity) +} + +' columns and rows + + cols = hp / 8 + rows = vp / 12 + + +VAR long cog[2] + +PUB start(BasePin, ScreenPtr, ColorPtr, CursorPtr, SyncPtr) : okay | i, j + +'' Start VGA driver - starts two COGs +'' returns false if two COGs not available +'' +'' BasePin = VGA starting pin (0, 8, 16, 24, etc.) +'' +'' ScreenPtr = Pointer to 8,192 bytes containing ASCII codes for each of the +'' 128x64 screen characters. Each byte's top bit controls color +'' inversion while the lower seven bits provide the ASCII code. +'' Screen memory is arranged left-to-right, top-to-bottom. +'' +'' screen byte example: %1_1000001 = inverse "A" +'' +'' ColorPtr = Pointer to 64 words which define the foreground and background +'' colors for each row. The lower byte of each word contains the +'' foreground RGB data for that row, while the upper byte +'' contains the background RGB data. The RGB data in each byte is +'' arranged as %RRGGBB00 (4 levels each). +'' +'' color word example: %%0020_3300 = gold on blue +'' +'' CursorPtr = Pointer to 6 bytes which control the cursors: +'' +'' bytes 0,1,2: X, Y, and MODE of cursor 0 +'' bytes 3,4,5: X, Y, and MODE of cursor 1 +'' +'' X and Y are in terms of screen characters +'' (left-to-right, top-to-bottom) +'' +'' MODE uses three bottom bits: +'' +'' %x00 = cursor off +'' %x01 = cursor on +'' %x10 = cursor on, blink slow +'' %x11 = cursor on, blink fast +'' %0xx = cursor is solid block +'' %1xx = cursor is underscore +'' +'' cursor example: 127, 63, %010 = blinking block in lower-right +'' +'' SyncPtr = Pointer to long which gets written with -1 upon each screen +'' refresh. May be used to time writes/scrolls, so that chopiness +'' can be avoided. You must clear it each time if you want to see +'' it re-trigger. + + 'if driver is already running, stop it + stop + + 'implant pin settings + reg_vcfg := $200000FF + (BasePin & %111000) << 6 + i := $FF << (BasePin & %011000) + j := BasePin & %100000 == 0 + reg_dira := i & j + reg_dirb := i & !j + + 'implant CNT value to sync COGs to + sync_cnt := cnt + $10000 + + 'implant pointers + longmove(@screen_base, @ScreenPtr, 3) + font_base := @font + + 'implant unique settings and launch first COG + vf_lines.byte := vf + vb_lines.byte := vb + font_third := 1 + cog[1] := cognew(@d0, SyncPtr) + 1 + + 'allow time for first COG to launch + waitcnt($2000 + cnt) + + 'differentiate settings and launch second COG + vf_lines.byte := vf+4 + vb_lines.byte := vb-4 + font_third := 0 + cog[0] := cognew(@d0, SyncPtr) + 1 + + 'if both COGs launched, return true + if cog[0] and cog[1] + return true + + 'else, stop any launched COG and return false + else + stop + + +PUB stop | i + +'' Stop VGA driver - frees two COGs + + repeat i from 0 to 1 + if cog[i] + cogstop(cog[i]~ - 1) + + +CON + + #1, scanbuff[128], scancode[128*2-1+3], maincode 'enumerate COG RAM usage + + main_size = $1F0 - maincode 'size of main program + + hv_inactive = (hn << 1 + vn) * $0101 'H,V inactive states + + +DAT + +'***************************************************** +'* Assembly language VGA high-resolution text driver * +'***************************************************** + +' This program runs concurrently in two different COGs. +' +' Each COG's program has different values implanted for front-porch lines and +' back-porch lines which surround the vertical sync pulse lines. This allows +' timed interleaving of their active display signals during the visible portion +' of the field scan. Also, they are differentiated so that one COG displays +' even four-line groups while the other COG displays odd four-line groups. +' +' These COGs are launched in the PUB 'start' and are programmed to synchronize +' their PLL-driven video circuits so that they can alternately prepare sets of +' four scan lines and then display them. The COG-to-COG switchover is seemless +' due to two things: exact synchronization of the two video circuits and the +' fact that all COGs' driven output states get OR'd together, allowing one COG +' to output lows during its preparatory state while the other COG effectively +' drives the pins to create the visible and sync portions of its scan lines. +' During non-visible scan lines, both COGs output together in unison. +' +' COG RAM usage: $000 = d0 - used to inc destination fields for indirection +' $001-$080 = scanbuff - longs which hold 4 scan lines +' $081-$182 = scancode - stacked WAITVID/SHR for fast display +' $183-$1EF = maincode - main program loop which drives display + + org 'set origin to $000 for start of program + +d0 long 1 << 9 'd0 always resides here at $000, executes as NOP + + +' Initialization code and data - after execution, space gets reused as scanbuff + + 'Move main program into maincode area + +:move mov $1EF,main_begin+main_size-1 + sub :move,d0s0 '(do reverse move to avoid overwrite) + djnz main_ctr,#:move + + 'Build scanbuff display routine into scancode + +:waitvid mov scancode+0,i0 'org scancode +:shr mov scancode+1,i1 'waitvid color,scanbuff+0 + add :waitvid,d1 'shr scanbuff+0,#8 + add :shr,d1 'waitvid color,scanbuff+1 + add i0,#1 'shr scanbuff+1,#8 + add i1,d0 '... + djnz scan_ctr,#:waitvid 'waitvid color,scanbuff+cols-1 + + mov scancode+cols*2-1,i2 'mov vscl,#hf + mov scancode+cols*2+0,i3 'waitvid hvsync,#0 + mov scancode+cols*2+1,i4 'jmp #scanret + + 'Init I/O registers and sync COGs' video circuits + + mov dira,reg_dira 'set pin directions + mov dirb,reg_dirb + movi frqa,#(pr / 5) << 2 'set pixel rate + mov vcfg,reg_vcfg 'set video configuration + mov vscl,#1 'set video to reload on every pixel + waitcnt sync_cnt,colormask 'wait for start value in cnt, add ~1ms + movi ctra,#%00001_110 'COGs in sync! enable PLLs now - NCOs locked! + waitcnt sync_cnt,#0 'wait ~1ms for PLLs to stabilize - PLLs locked! + mov vscl,#100 'insure initial WAITVIDs lock cleanly + + 'Jump to main loop + + jmp #vsync 'jump to vsync - WAITVIDs will now be locked! + + 'Data + +d0s0 long 1 << 9 + 1 +d1 long 1 << 10 +main_ctr long main_size +scan_ctr long cols + +i0 waitvid x,scanbuff+0 +i1 shr scanbuff+0,#8 +i2 mov vscl,#hf +i3 waitvid hvsync,#0 +i4 jmp #scanret + +reg_dira long 0 'set at runtime +reg_dirb long 0 'set at runtime +reg_vcfg long 0 'set at runtime +sync_cnt long 0 'set at runtime + + 'Directives + + fit scancode 'make sure initialization code and data fit +main_begin org maincode 'main code follows (gets moved into maincode) + + +' Main loop, display field - each COG alternately builds and displays four scan lines + +vsync mov x,#vs 'do vertical sync lines + call #blank_vsync + +vb_lines mov x,#vb 'do vertical back porch lines (# set at runtime) + call #blank_vsync + + mov screen_ptr,screen_base 'reset screen pointer to upper-left character + mov color_ptr,color_base 'reset color pointer to first row + mov row,#0 'reset row counter for cursor insertion + mov fours,#rows * 3 / 2 'set number of 4-line builds for whole screen + + 'Build four scan lines into scanbuff + +fourline mov font_ptr,font_third 'get address of appropriate font section + shl font_ptr,#7+2 + add font_ptr,font_base + + movd :pixa,#scanbuff-1 'reset scanbuff address (pre-decremented) + movd :pixb,#scanbuff-1 + + mov y,#2 'must build scanbuff in two sections because + mov vscl,vscl_line2x '..pixel counter is limited to twelve bits + +:halfrow waitvid underscore,#0 'output lows to let other COG drive VGA pins + mov x,#cols/2 '..for 2 scan lines, ready for half a row + +:column rdbyte z,screen_ptr 'get character from screen memory + ror z,#7 'get inverse flag into bit 0, keep chr high + shr z,#32-7-2 wc 'get inverse flag into c, chr into bits 8..2 + add z,font_ptr 'add font section address to point to 8*4 pixels + add :pixa,d0 'increment scanbuff destination addresses + add :pixb,d0 + add screen_ptr,#1 'increment screen memory address +:pixa rdlong scanbuff,z 'read pixel long (8*4) into scanbuff +:pixb if_nc xor scanbuff,longmask 'invert pixels according to inverse flag + djnz x,#:column 'another character in this half-row? + + djnz y,#:halfrow 'loop to do 2nd half-row, time for 2nd WAITVID + + sub screen_ptr,#cols 'back up to start of same row in screen memory + + 'Insert cursors into scanbuff + + mov z,#2 'ready for two cursors + +:cursor rdbyte x,cursor_base 'x in range? + add cursor_base,#1 + cmp x,#cols wc + + rdbyte y,cursor_base 'y match? + add cursor_base,#1 + cmp y,row wz + + rdbyte y,cursor_base 'get cursor mode + add cursor_base,#1 + + if_nc_or_nz jmp #:nocursor 'if cursor not in scanbuff, no cursor + + add x,#scanbuff 'cursor in scanbuff, set scanbuff address + movd :xor,x + + test y,#%010 wc 'get mode bits into flags + test y,#%001 wz + if_nc_and_z jmp #:nocursor 'if cursor disabled, no cursor + + if_c_and_z test slowbit,cnt wc 'if blink mode, get blink state + if_c_and_nz test fastbit,cnt wc + + test y,#%100 wz 'get box or underscore cursor piece + if_z mov x,longmask + if_nz mov x,underscore + if_nz cmp font_third,#2 wz 'if underscore, must be last font section + +:xor if_nc_and_z xor scanbuff,x 'conditionally xor cursor into scanbuff + +:nocursor djnz z,#:cursor 'second cursor? + + sub cursor_base,#3*2 'restore cursor base + + 'Display four scan lines from scanbuff + + rdword x,color_ptr 'get color pattern for current row + and x,colormask 'mask away hsync and vsync signal states + or x,hv 'insert inactive hsync and vsync states + + mov y,#4 'ready for four scan lines + +scanline mov vscl,vscl_chr 'set pixel rate for characters + jmp #scancode 'jump to scanbuff display routine in scancode +scanret mov vscl,#hs 'do horizontal sync pixels + waitvid hvsync,#1 '#1 makes hsync active + mov vscl,#hb 'do horizontal back porch pixels + waitvid hvsync,#0 '#0 makes hsync inactive + shr scanbuff+cols-1,#8 'shift last column's pixels right by 8 + djnz y,#scanline 'another scan line? + + 'Next group of four scan lines + + add font_third,#2 'if font_third + 2 => 3, subtract 3 (new row) + cmpsub font_third,#3 wc 'c=0 for same row, c=1 for new row + if_c add screen_ptr,#cols 'if new row, advance screen pointer + if_c add color_ptr,#2 'if new row, advance color pointer + if_c add row,#1 'if new row, increment row counter + djnz fours,#fourline 'another 4-line build/display? + + 'Visible section done, do vertical sync front porch lines + + wrlong longmask,par 'write -1 to refresh indicator + +vf_lines mov x,#vf 'do vertical front porch lines (# set at runtime) + call #blank + + jmp #vsync 'new field, loop to vsync + + 'Subroutine - do blank lines + +blank_vsync xor hvsync,#$101 'flip vertical sync bits + +blank mov vscl,hx 'do blank pixels + waitvid hvsync,#0 + 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? +blank_ret +blank_vsync_ret ret + + 'Data + +screen_base long 0 'set at runtime (3 contiguous longs) +color_base long 0 'set at runtime +cursor_base long 0 'set at runtime + +font_base long 0 'set at runtime +font_third long 0 'set at runtime + +hx long hp 'visible pixels per scan line +vscl_line2x long (hp + hf + hs + hb) * 2 'total number of pixels per 2 scan lines +vscl_chr long 1 << 12 + 8 '1 clock per pixel and 8 pixels per set +colormask long $FCFC 'mask to isolate R,G,B bits from H,V +longmask long $FFFFFFFF 'all bits set +slowbit long 1 << 25 'cnt mask for slow cursor blink +fastbit long 1 << 24 'cnt mask for fast cursor blink +underscore long $FFFF0000 'underscore cursor pattern +hv long hv_inactive '-H,-V states +hvsync long hv_inactive ^ $200 '+/-H,-V states + + 'Uninitialized data + +screen_ptr res 1 +color_ptr res 1 +font_ptr res 1 + +x res 1 +y res 1 +z res 1 + +row res 1 +fours res 1 + + +' 8 x 12 font - characters 0..127 +' +' Each long holds four scan lines of a single character. The longs are arranged into +' groups of 128 which represent all characters (0..127). There are three groups which +' each contain a vertical third of all characters. They are ordered top, middle, and +' bottom. +' +' NOTE: MSB set inverts the character. i.e. $31 = a 1 $B1 = an inverted 1 +' +' char 0 = ← left arrow +' char 1 = → right arrow +' char 2 = ↑ up arrow +' char 3 = ↓ down arrow +' char 4 = empty circle bullet (radio button) +' char 5 = filled circle bullet (radio button) +' char 6 = empty square bullet (check box) +' char 7 = filled square bullet (check box) +' char 8 = ▶ right triangle bullet +' char 9 = • small bullet +' char 10 = ┌ top left corner (but curved) +' char 11 = ┐ top right corner (but curved) +' char 12 = └ bottom left corner (but curved) +' char 13 = ┘ bottom right corner (but curved) +' char 14 = ─ horizontal line +' char 15 = │ vertical line +' char 16 = ┬ top 'tee' +' char 17 = ┴ bottom 'tee' +' char 18 = ├ left 'tee' +' char 19 = ┤ right 'tee' +' char 20 = ┼ cross point + +font long + +long $0C080000,$30100000,$7E3C1800,$18181800,$81423C00,$99423C00,$8181FF00,$E7C3FF00 'top +long $1E0E0602,$1C000000,$00000000,$00000000,$18181818,$18181818,$00000000,$18181818 +long $00000000,$18181818,$18181818,$18181818,$18181818,$00FFFF00,$CC993366,$66666666 +long $AA55AA55,$0F0F0F0F,$0F0F0F0F,$0F0F0F0F,$0F0F0F0F,$00000000,$00000000,$00000000 +long $00000000,$3C3C1800,$77666600,$7F363600,$667C1818,$46000000,$1B1B0E00,$1C181800 +long $0C183000,$180C0600,$66000000,$18000000,$00000000,$00000000,$00000000,$60400000 +long $73633E00,$1E181000,$66663C00,$60663C00,$3C383000,$06067E00,$060C3800,$63637F00 +long $66663C00,$66663C00,$1C000000,$00000000,$18306000,$00000000,$180C0600,$60663C00 +long $63673E00,$66663C00,$66663F00,$63663C00,$66361F00,$06467F00,$06467F00,$63663C00 +long $63636300,$18183C00,$30307800,$36666700,$06060F00,$7F776300,$67636300,$63361C00 +long $66663F00,$63361C00,$66663F00,$66663C00,$185A7E00,$66666600,$66666600,$63636300 +long $66666600,$66666600,$31637F00,$0C0C3C00,$03010000,$30303C00,$361C0800,$00000000 +long $0C000000,$00000000,$06060700,$00000000,$30303800,$00000000,$0C6C3800,$00000000 +long $06060700,$00181800,$00606000,$06060700,$18181E00,$00000000,$00000000,$00000000 +long $00000000,$00000000,$00000000,$00000000,$0C080000,$00000000,$00000000,$00000000 +long $00000000,$00000000,$00000000,$18187000,$18181800,$18180E00,$73DBCE00,$18180000 + +long $080C7E7E,$10307E7E,$18181818,$7E181818,$81818181,$99BDBDBD,$81818181,$E7BD99BD 'middle +long $1E3E7E3E,$1C3E3E3E,$30F0C000,$0C0F0300,$00C0F030,$00030F0C,$00FFFF00,$18181818 +long $18FFFF00,$00FFFF18,$18F8F818,$181F1F18,$18FFFF18,$00FFFF00,$CC993366,$66666666 +long $AA55AA55,$FFFF0F0F,$F0F00F0F,$0F0F0F0F,$00000F0F,$FFFF0000,$F0F00000,$0F0F0000 +long $00000000,$0018183C,$00000033,$7F363636,$66603C06,$0C183066,$337B5B0E,$0000000C +long $0C060606,$18303030,$663CFF3C,$18187E18,$00000000,$00007E00,$00000000,$060C1830 +long $676F6B7B,$18181818,$0C183060,$60603860,$307F3336,$60603E06,$66663E06,$0C183060 +long $66763C6E,$60607C66,$1C00001C,$00001C1C,$180C060C,$007E007E,$18306030,$00181830 +long $033B7B7B,$66667E66,$66663E66,$63030303,$66666666,$06263E26,$06263E26,$63730303 +long $63637F63,$18181818,$33333030,$36361E36,$66460606,$63636B7F,$737B7F6F,$63636363 +long $06063E66,$7B636363,$66363E66,$66301C06,$18181818,$66666666,$66666666,$366B6B63 +long $663C183C,$18183C66,$43060C18,$0C0C0C0C,$30180C06,$30303030,$00000063,$00000000 +long $0030381C,$333E301E,$6666663E,$0606663C,$3333333E,$067E663C,$0C0C3E0C,$3333336E +long $66666E36,$1818181C,$60606070,$361E3666,$18181818,$6B6B6B3F,$6666663E,$6666663C +long $6666663B,$3333336E,$066E7637,$300C663C,$0C0C0C7E,$33333333,$66666666,$6B6B6363 +long $1C1C3663,$66666666,$0C30627E,$180C060C,$18181818,$18306030,$00000000,$0018187E + +long $00000000,$00000000,$00001818,$0000183C,$00003C42,$00003C42,$0000FF81,$0000FFC3 'bottom +long $0002060E,$00000000,$18181818,$18181818,$00000000,$00000000,$00000000,$18181818 +long $18181818,$00000000,$18181818,$18181818,$18181818,$00FFFF00,$CC993366,$66666666 +long $AA55AA55,$FFFFFFFF,$F0F0F0F0,$0F0F0F0F,$00000000,$FFFFFFFF,$F0F0F0F0,$0F0F0F0F +long $00000000,$00001818,$00000000,$00003636,$0018183E,$00006266,$00006E3B,$00000000 +long $00003018,$0000060C,$00000000,$00000000,$0C181C1C,$00000000,$00001C1C,$00000103 +long $00003E63,$00007E18,$00007E66,$00003C66,$00007830,$00003C66,$00003C66,$00000C0C +long $00003C66,$00001C30,$0000001C,$0C181C1C,$00006030,$00000000,$0000060C,$00001818 +long $00003E07,$00006666,$00003F66,$00003C66,$00001F36,$00007F46,$00000F06,$00007C66 +long $00006363,$00003C18,$00001E33,$00006766,$00007F66,$00006363,$00006363,$00001C36 +long $00000F06,$00603C36,$00006766,$00003C66,$00003C18,$00003C66,$0000183C,$00003636 +long $00006666,$00003C18,$00007F63,$00003C0C,$00004060,$00003C30,$00000000,$FFFF0000 +long $00000000,$00006E33,$00003B66,$00003C66,$00006E33,$00003C66,$00001E0C,$1E33303E +long $00006766,$00007E18,$3C666660,$00006766,$00007E18,$00006B6B,$00006666,$00003C66 +long $0F063E66,$78303E33,$00000F06,$00003C66,$0000386C,$00006E33,$0000183C,$00003636 +long $00006336,$1C30607C,$00007E46,$00007018,$00001818,$00000E18,$00000000,$0000007E + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/gui-demo/vga-vid.spin b/source/gui-demo/vga-vid.spin new file mode 100644 index 0000000..6626d01 --- /dev/null +++ b/source/gui-demo/vga-vid.spin @@ -0,0 +1,545 @@ +{{ +┌────────────────────────────────────────┬────────────────┬────────────────────────┬──────────────────┐ +│ VGA 1024x768 Tile Driver v0.9 │ by Chip Gracey │ (C)2006 Parallax, Inc. │ 11 November 2006 │ +├────────────────────────────────────────┴────────────────┴────────────────────────┴──────────────────┤ +│ │ +│ This object generates a 1024x768 VGA display from a 64x48 array of 16x16-pixel 4-color tiles. │ +│ It requires two cogs (or three with optional cursor enabled) and at least 80 MHz. │ +│ │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +}} +CON + +' 1024 x 768 @ 60Hz settings + + hp = 1024 'horizontal pixels + vp = 768 'vertical pixels + hf = 16 'horizontal front porch pixels + hs = 96 'horizontal sync pixels + hb = 176 'horizontal back porch pixels + vf = 1 'vertical front porch lines + vs = 3 'vertical sync lines + vb = 28 'vertical back porch lines + pr = 60 'pixel rate in MHz at 80MHz system clock (5MHz granularity) + + ht = hp + hf + hs + hb 'total scan line pixels + +' Tile array + + xtiles = hp / 16 + ytiles = vp / 16 + + COLS = 64 + ROWS = 48 + +VAR + + long cog[3] + + long dira_ '9 contiguous longs + long dirb_ + long vcfg_ + long cnt_ + long array_ptr_ + long color_ptr_ + long cursor_ptr_ + long sync_ptr_ + long mode_ + + +PUB start(base_pin, array_ptr, color_ptr, cursor_ptr, sync_ptr, mode) : okay | i, j + +'' Start driver - starts two or three cogs +'' returns false if cogs not available +'' +'' base_pin = First of eight VGA pins, must be a multiple of eight (0, 8, 16, 24, etc): +'' +'' 240Ω 240Ω 240Ω 240Ω +'' +7 ───┳─ Red +5 ───┳─ Green +3 ───┳─ Blue +1 ── H +'' 470Ω │ 470Ω │ 470Ω │ 240Ω +'' +6 ───┘ +4 ───┘ +2 ───┘ +0 ── V +'' +'' array_ptr = Pointer to 3,072 long-aligned words, organized as 64 across by 48 down, +'' which will serve as the tile array. Each word specifies a tile bitmap and +'' a color palette for its tile area. The top 10 bits of each word form the +'' base address of a 16-long tile bitmap, while the lower 6 bits select a +'' color palette for the bitmap. For example, $B2E5 would specify the tile +'' bitmap spanning $B2C0..$B2FF and color palette $25. +'' +'' color_ptr = Pointer to 64 longs which will define the 64 color palettes. The RGB data +'' in each long is arranged as %%RGBx_RGBx_RGBx_RGBx with the sub-bytes 3..0 +'' providing the color data for pixel values %11..%00, respectively: +'' +'' %%3330_0110_0020_3300: %11=white, %10=dark cyan, %01=blue, %00=gold +'' +'' cursor_ptr = Pointer to 4 longs which will control the cursor, or 0 to disable the +'' cursor. If a pointer is given, an extra cog will be started to generate +'' the cursor overlay. Here are the 4 longs that control the cursor: +'' +'' cursor_x - X position of cursor: ..0..1023.. (left to right) +'' cursor_y - Y position of cursor: ..0..767.. (bottom to top) +'' +'' cursor_color - Cursor color to be OR'd to background color as %%RGBx: +'' %%3330=white, %%2220 or %%1110=translucent, %%0000=off +'' +'' cursor_shape - 0 for arrow, 1 for crosshair, or pointer to a cursor +'' definition. A cursor definition consists of 32 longs +'' containing a 32x32 pixel cursor image, followed by two +'' bytes which define the X and Y center-pixel offsets +'' within the image. +'' +'' sync_ptr = Pointer to a long which will be set to -1 after each refresh, or 0 to +'' disable this function. This is useful in advanced applications where +'' awareness of display timing is important. +'' +'' mode = 0 for normal 16x16 pixel tiles or 1 for taller 16x32 pixel tiles. Mode 1 +'' is useful for displaying the internal font while requiring half the array +'' memory; however, the 3-D bevel characters will not be usable because of +'' the larger vertical tile granularity of this mode. + + 'If driver is already running, stop it + stop + + 'Ready i/o settings + i := $FF << (base_pin & %011000) + j := base_pin & %100000 == 0 + dira_ := i & j + dirb_ := i & !j + vcfg_ := $300000FF + (base_pin & %111000) << 6 + + 'Ready cnt value to sync cogs by + cnt_ := cnt + $100000 + + 'Ready pointers and mode + longmove(@array_ptr_, @array_ptr, 5) + + 'Launch cogs, abort if error + repeat i from 0 to 2 + if i == 2 'cursor cog? + ifnot cursor_ptr 'cursor enabled? + quit 'if not, quit loop + waitcnt($2000 + cnt) 'cursor cog, allow prior cog to launch + vcfg_ ^= $10000000 'set two-color mode + array_ptr_~ 'flag cursor function + ifnot cog[i] := cognew(@entry, @dira_ + i << 15) + 1 + stop + return {false} + + 'Successful + return true + + +PUB stop | i + +'' Stop driver - frees cogs + + 'If already running, stop any VGA cogs + repeat i from 0 to 2 + if cog[i] + cogstop(cog[i]~ - 1) + + +DAT + +' ┌─────────────────────────────┐ +' │ Initialization - all cogs │ +' └─────────────────────────────┘ + + org + +' Move field loop into position + +entry mov field,field_code + add entry,d0s0_ + djnz regs,#entry + +' Acquire settings + + mov regs,par 'dira_ ─ dira + cmpsub regs,bit15 wc 'dirb_ ─ dirb +:next movd :read,sprs 'vcfg_ ─ vcfg + or :read,d8_d4 'cnt_ ─ cnt + shr sprs,#4 'array_ptr_ ─ ctrb +:read rdlong dira,regs 'color_ptr_ ─ frqb + add regs,#4 'cursor_ptr_ ─ vscl + tjnz sprs,#:next 'sync_ptr_ ─ phsb + + sumc vf_lines,#2 'alter scan line settings by cog + sumnc vb_lines,#2 + sumnc tile_line,#2 * 4 + + rdlong regs,regs wz 'if mode not 0, set tile size to 16 x 32 pixels + if_nz movs tile_bytes,#32 * 4 + if_nz shr array_bytes,#1 + + mov regs,vscl 'save cursor pointer + +' Synchronize all cogs' video circuits so that waitvid's will be pixel-locked + + movi frqa,#(pr / 5) << 2 'set pixel rate (VCO runs at 2x) + mov vscl,#1 'set video shifter to reload on every pixel + waitcnt cnt,d8_d4 'wait for sync count, add ~3ms - cogs locked! + movi ctra,#%00001_110 'enable PLLs now - NCOs locked! + waitcnt cnt,#0 'wait ~3ms for PLLs to stabilize - PLLs locked! + mov vscl,#100 'subsequent WAITVIDs will now be pixel-locked! + +' Determine if this cog is to perform one of two field functions or the cursor function + + tjnz ctrb,#vsync 'if array ptr, jump to field function + 'else, cursor function follows + +' ┌─────────────────────────┐ +' │ Cursor Loop - one cog │ +' └─────────────────────────┘ + +' Do vertical sync lines minus three + +cursor mov par,#vf + vs + vb - 6 + +:loop mov vscl,vscl_line +:vsync waitvid ccolor,#0 + djnz par,#:vsync + +' Do three lines minus horizontal back porch pixels to buy a big block of time + + mov vscl,vscl_three_lines_mhb + waitvid ccolor,#0 + +' Get cursor data + + rdlong cx,regs 'get cursor x + add regs,#4 + rdlong cy,regs 'get cursor y + add regs,#4 + rdlong ccolor,regs 'get cursor color + add regs,#4 + rdlong cshape,regs 'get cursor shape + sub regs,#3 * 4 + + and ccolor,#$FC 'trim and justify cursor color + shl ccolor,#8 + +' Build cursor pixels + + mov par,#32 'ready for 32 cursor segments + movd :pix,#cpix + mov cnt,cshape + +:pixloop cmp cnt,#1 wc, wz 'arrow, crosshair, or custom cursor? + if_a jmp #:custom + if_e jmp #:crosshair + + cmp par,#32 wz 'arrow + cmp par,#32-21 wc + if_z mov cseg,h80000000 + if_nz_and_nc sar cseg,#1 + if_nz_and_c shl cseg,#2 + mov coff,#0 + jmp #:pix + +:crosshair cmp par,#32-15 wz 'crosshair + if_ne mov cseg,h00010000 + if_e neg cseg,#2 + cmp par,#1 wz + if_e mov cseg,#0 + mov coff,h00000F0F + jmp #:pix + +:custom rdlong cseg,cshape 'custom + add cshape,#4 + rdlong coff,cshape + +:pix mov cpix,cseg 'save segment into pixels + add :pix,d0 + + djnz par,#:pixloop 'another segment? + +' Compute cursor position + + mov cseg,coff 'apply cursor center-pixel offsets + and cseg,#$FF + sub cx,cseg + shr coff,#8 + and coff,#$FF + add cy,coff + + cmps cx,neg31 wc 'if x out of range, hide cursor via y + if_nc cmps pixels_m1,cx wc + if_c neg cy,#1 + + mov cshr,#0 'adjust for left-edge clipping + cmps cx,#0 wc + if_c neg cshr,cx + if_c mov cx,#0 + + mov cshl,#0 'adjust for right-edge clipping + cmpsub cx,pixels_m32 wc + if_c mov cshl,cx + if_c mov cx,pixels_m32 + + add cx,#hb 'bias x and y for display + sub cy,lines_m1 + +' Do visible lines with cursor + + mov par,lines 'ready for visible scan lines + +:line andn cy,#$1F wz, nr 'check if scan line in cursor range + + if_z movs :seg,cy 'if in range, get cursor pixels + if_z add :seg,#cpix + if_nz mov cseg,#0 'if out of range, use blank pixels +:seg if_z mov cseg,cpix + if_z rev cseg,#0 'reverse pixels so they map sensibly + if_z shr cseg,cshr 'perform any edge clipping on pixels + if_z shl cseg,cshl + + mov vscl,cx 'do left blank pixels (hb+cx) + waitvid ccolor,#0 + + mov vscl,vscl_cursor 'do cursor pixels (32) + waitvid ccolor,cseg + + mov vscl,vscl_line_m32 'do right blank pixels (hp+hf+hs-32-cx) + sub vscl,cx + waitvid ccolor,#0 + + add cy,#1 'another scan line? + djnz par,#:line + +' Do horizontal back porch pixels and loop + + mov vscl,#hb + waitvid ccolor,#0 + + mov par,#vf + vs + vb - 3 'ready to do vertical sync lines + jmp #:loop + +' Cursor data + +vscl_line long ht 'total pixels per scan line +vscl_three_lines_mhb long ht * 3 - hb 'total pixels per three scan lines minus hb +vscl_line_m32 long ht - 32 'total pixels per scan line minus 32 +vscl_cursor long 1 << 12 + 32 '32 pixels per cursor with 1 clock per pixel +lines long vp 'visible scan lines +lines_m1 long vp - 1 'visible scan lines minus 1 +pixels_m1 long hp - 1 'visible pixels minus 1 +pixels_m32 long hp - 32 'visible pixels minus 32 +neg31 long -31 + +h80000000 long $80000000 'arrow/crosshair cursor data +h00010000 long $00010000 +h00000F0F long $00000F0F + +' Initialization data + +d0s0_ long 1 << 9 + 1 'd and s field increments +regs long $1F0 - field 'number of registers in field loop space +sprs long $DFB91E76 'phsb/vscl/frqb/ctrb/cnt/vcfg/dirb/dira nibbles +bit15 long $8000 'bit15 mask used to differentiate cogs in par +d8_d4 long $0003E000 'bit8..bit4 mask for d field + +field_code 'field loop code begins at this offset + +' Undefined cursor data + +cx res 1 +cy res 1 +ccolor res 1 +cshape res 1 +coff res 1 +cseg res 1 +cshr res 1 +cshl res 1 +cpix res 32 + + +' ┌─────────────────────────┐ +' │ Field Loop - two cogs │ +' └─────────────────────────┘ + + org + +' Allocate buffers + +palettes res 64 'palettes of colors +colors res xtiles 'colors for tile row +pixels0 res xtiles 'pixels for tile row line +0 +pixels1 res xtiles 'pixels for tile row line +1 +pixels2 res xtiles 'pixels for tile row line +2 +pixels3 res xtiles 'pixels for tile row line +3 + +' Each cog alternately builds and displays four scan lines + +field mov cnt,#ytiles * 4 / 2 'ready number of four-scan-line builds/displays + +' Build four scan lines + +build_4y movd col0,#colors+0 'reset pointers for scan line buffers + movd col1,#colors+1 + movd pix0,#pixels0+0 + movd pix1,#pixels1+0 + movd pix2,#pixels2+0 + movd pix3,#pixels3+0 + movd pix4,#pixels0+1 + movd pix5,#pixels1+1 + movd pix6,#pixels2+1 + movd pix7,#pixels3+1 + + mov ina,#2 'four scan lines require two waitvid's + +build_32x mov vscl,vscl_two_lines 'output lows for two scan lines so other cog +:zero waitvid :zero,#0 '..can display while this cog builds (twice) + + mov inb,#xtiles / 2 / 2 'build four scan lines for half a row + +build_2x rdlong vscl,ctrb 'get pair of words from the tile array + + movs col0,vscl 'get color bits from even tile + andn col0,#$1C0 + + andn vscl,#$3F 'strip color bits and add tile line offset + add vscl,tile_line + +col0 mov colors+0,palettes 'get even tile color + add col0,d1 + +pix0 rdlong pixels0+0,vscl 'get line +0 even tile pixels + add pix0,d1 + add vscl,#4 + +pix1 rdlong pixels1+0,vscl 'get line +1 even tile pixels + add pix1,d1 + add vscl,#4 + +pix2 rdlong pixels2+0,vscl 'get line +2 even tile pixels + add pix2,d1 + add vscl,#4 + +pix3 rdlong pixels3+0,vscl 'get line +3 even tile pixels + add pix3,d1 + + add ctrb,#2 * 2 'point to next pair of tile words + shr vscl,#16 'shift odd tile word into position + + movs col1,vscl 'get color bits from odd tile + andn col1,#$1C0 + + andn vscl,#$3F 'strip color bits and add tile line offset + add vscl,tile_line + +col1 mov colors+1,palettes 'get odd tile color + add col1,d1 + +pix4 rdlong pixels0+1,vscl 'get line +0 odd tile pixels + add pix4,d1 + add vscl,#4 + +pix5 rdlong pixels1+1,vscl 'get line +1 odd tile pixels + add pix5,d1 + add vscl,#4 + +pix6 rdlong pixels2+1,vscl 'get line +2 odd tile pixels + add pix6,d1 + add vscl,#4 + +pix7 rdlong pixels3+1,vscl 'get line +3 odd tile pixels + add pix7,d1 + djnz inb,#build_2x 'loop for next tile pair (48 inst/loop) + + djnz ina,#build_32x 'if first half done, loop for 2nd waitvid + + sub ctrb,#xtiles * 2 'back up to start of same row + +' Display four scan lines + + mov inb,#4 'ready for four scan lines + movs :waitvid,#pixels0 'reset waitvid pixel pointer + +:line mov ina,#xtiles 'ready for tiles + movd :waitvid,#colors 'reset waitvid color pointer + mov vscl,vscl_tile 'set pixel rate for tiles + +:tile cmp ina,#1 wz 'check if last tile + add :waitvid,d0s0 'advance pointers (waitvid already read) +:waitvid waitvid colors,pixels0 'do tile slice + if_nz djnz ina,#:tile 'strange loop allows hsync timing and ina=1 + + call #hsync 'do horizontal sync (ina=1) + + djnz inb,#:line 'another scan line? + +' Another four scan lines? + + add tile_line,#8 * 4 'advance eight scan lines within tile row +tile_bytes cmpsub tile_line,#16 * 4 wc 'tile row done? (# doubled for mode 1) + if_c add ctrb,#xtiles * 2 'if done, advance array pointer to next row + + djnz cnt,#build_4y 'another four scan lines? + + sub ctrb,array_bytes 'display done, reset array pointer to top row + +' Visible section done, handle sync indicator + + cmp cnt,phsb wz 'sync enabled? (cnt=0) + if_nz wrlong neg1,phsb 'if so, write -1 to sync indicator + +' Do vertical sync lines and loop + +vf_lines mov ina,#vf + 2 'do vertical front porch lines (adjusted ±2) + call #blank + +vsync mov ina,#vs 'do vertical sync lines + call #blank_vsync + +vb_lines mov ina,#vb - 2 'do vertical back porch lines (adjusted ±2) + movs blank_vsync_ret,#field '(loop to field, blank_vsync follows) + +' Subroutine - do blank lines + +blank_vsync xor hv_sync,#$0101 'flip vertical sync bits + +blank mov vscl,vscl_blank 'do horizontal blank pixels + waitvid hv_sync,#0 + +hsync mov vscl,#hf 'do horizontal front porch pixels + waitvid hv_sync,#0 + + mov vscl,#hs 'do horizontal sync pixels + waitvid hv_sync,#1 + + rdlong vscl,frqb 'update another palette + and vscl,color_mask +:palette mov palettes,vscl + add :palette,d0 + add frqb,#4 + add par,count_64 wc + if_c movd :palette,#palettes + if_c sub frqb,#64 * 4 + + mov vscl,#hb 'do horizontal back porch pixels + waitvid hv_sync,#0 + + djnz ina,#blank 'another blank line? +hsync_ret +blank_ret +blank_vsync_ret ret + +' Data + +d0s0 long 1 << 9 + 1 'd and s field increments +d0 long 1 << 9 'd field increment +d1 long 2 << 9 'd field double increment + +tile_line long 2 * 4 'tile line offset (adjusted ±2 * 4) +array_bytes long xtiles * ytiles * 2 'number of bytes in tile array + +vscl_two_lines long ht * 2 'total pixels per two scan lines +vscl_tile long 1 << 12 + 16 '16 pixels per tile with 1 clock per pixel +vscl_blank long hp 'visible pixels per scan line + +hv_sync long $0200 '+/-H,-V states +count_64 long $04000000 'addend that sets carry every 64th addition +color_mask long $FCFCFCFC 'mask to isolate R,G,B bits from H,V +neg1 long $FFFFFFFF 'negative 1 to be written to sync indicator diff --git a/source/plexbus/joystick.spin b/source/plexbus/joystick.spin new file mode 100644 index 0000000..a715332 --- /dev/null +++ b/source/plexbus/joystick.spin @@ -0,0 +1,62 @@ +{{ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Ingo Kripahle │ +│ Copyright (c) 2010 Ingo Kripahle │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : drohne235@googlemail.com +System : TriOS +Name : +Chip : Regnatix +Typ : Programm +Version : +Subversion : +Funktion : +Komponenten : - +COG's : - +Logbuch : +Kommandoliste : +Notizen : + +}} + +OBJ + ios: "reg-ios" + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + +PUB main | j + + ios.start + repeat + ios.printbin(ios.joy,8) + ios.printnl + until ios.key + ios.stop + +DAT + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/plexbus/map.spin b/source/plexbus/map.spin new file mode 100644 index 0000000..811fddc --- /dev/null +++ b/source/plexbus/map.spin @@ -0,0 +1,91 @@ +{{ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Ingo Kripahle │ +│ Copyright (c) 2010 Ingo Kripahle │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : drohne235@googlemail.com +System : TriOS +Name : +Chip : Regnatix +Typ : Programm +Version : +Subversion : +Funktion : +Komponenten : - +COG's : - +Logbuch : +Kommandoliste : +Notizen : + +}} + +OBJ + ios: "reg-ios" + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + +PUB main | ack,adr,n + +' anzeige einer echtzeitkarte aller 128 slaves am bus +' praktisch um die bausteine zu korrekt zu jumpern + + ios.start + ios.plxHalt + + n := 0 + ios.curoff + ios.printcls + repeat + ios.curhome + ios.printnl + ios.print(string(" 0123456789ABCDEF")) + ios.printnl + repeat adr from 0 to 127 + + 'ios.plxstart + 'ack := ios.plxwrite(adr<<1) + 'ios.plxstop + ack := ios.plxping(adr) + + if n == 0 + ios.printhex(adr,2) + ios.printchar(" ") + if ack + ios.printqchar("┼") + else + ios.printqchar("•") + if n++ == 15 + ios.printnl + n := 0 + until ios.key + ios.stop + + + +DAT + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/plexbus/paddle.spin b/source/plexbus/paddle.spin new file mode 100644 index 0000000..e66b6dc --- /dev/null +++ b/source/plexbus/paddle.spin @@ -0,0 +1,72 @@ +{{ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Ingo Kripahle │ +│ Copyright (c) 2010 Ingo Kripahle │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : drohne235@googlemail.com +System : TriOS +Name : +Chip : Regnatix +Typ : Programm +Version : +Subversion : +Funktion : +Komponenten : - +COG's : - +Logbuch : +Kommandoliste : +Notizen : + +}} + +OBJ + ios: "reg-ios" + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + +PUB main | n,p + + ios.start + repeat + ' paddle-wert einlesen + ' obere 8 bit = digtale kontakte + ' untere 8 bit = analogwert + n := ios.paddle + ' gesamtwert anzeigen + ios.printhex(n,4) + 'analogwert abtrenne + p := n & $0ff + 'balken ausgeben + repeat p/5 + ios.printchar("*") + ios.printnl + until ios.key + ios.stop + +DAT + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/plexbus/port-io.spin b/source/plexbus/port-io.spin new file mode 100644 index 0000000..9972f9d --- /dev/null +++ b/source/plexbus/port-io.spin @@ -0,0 +1,83 @@ +{{ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Ingo Kripahle │ +│ Copyright (c) 2010 Ingo Kripahle │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : drohne235@googlemail.com +System : TriOS +Name : +Chip : Regnatix +Typ : Programm +Version : +Subversion : +Funktion : +Komponenten : - +COG's : - +Logbuch : +Kommandoliste : +Notizen : + +}} + +OBJ + ios: "reg-ios" + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + +PUB main | n + +' demo für die direkte ansteuerung der ports +' es wird port 1 eingelesen und an port 3 an den angeschlossenen +' led's ausgegeben/angezeigt + + ios.start + + 'poller in administra anhalten und i2c-bus anfordern + ios.plxHalt + + repeat + 'port auslesen + n := ios.plxIn($20) 'pcf8574 + + 'port aus led's ausgeben + ios.plxOut($22,n) 'pcf8574 + + 'zusätzlich den wert auf dem screen ausgeben + ios.printbin(n,8) + ios.printnl + + until ios.key + ios.stop + + 'wenn nach den i2c-operationen weiter automatisch joysticks etc. + 'abgefragt werden, muss der bus wieder freigegeben werden + ios.plxRun + + +DAT + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/plexbus/port-test.spin b/source/plexbus/port-test.spin new file mode 100644 index 0000000..7d54048 --- /dev/null +++ b/source/plexbus/port-test.spin @@ -0,0 +1,112 @@ +{{ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Ingo Kripahle │ +│ Copyright (c) 2010 Ingo Kripahle │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : drohne235@googlemail.com +System : TriOS +Name : +Chip : Regnatix +Typ : Programm +Version : +Subversion : +Funktion : +Komponenten : - +COG's : - +Logbuch : +Kommandoliste : +Notizen : + +}} + +OBJ + ios: "reg-ios" + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + +PUB main | p1,p2,p3,a0,a1,a2,a3 + + ios.start + ios.plxHalt + + ios.curoff + ios.printcls + repeat + ios.curhome + ios.printnl + p1 := ios.plxIn($20) + p2 := ios.plxIn($21) + p3 := ios.plxIn($22) + a0 := ios.plxch($48,0) + a1 := ios.plxch($48,1) + a2 := ios.plxch($48,2) + a3 := ios.plxch($48,3) + print_port(1,p1) + print_port(2,p2) + print_port(3,p3) + ios.printnl + print_chan(0,a0) + print_chan(1,a1) + print_chan(2,a2) + print_chan(3,a3) + ios.plxout($3A,!(cnt>>23)) + until ios.key + ios.stop + +PRI print_chan(cnr,wert) + + ios.print(string("A/D ")) + ios.printdec(cnr) + ios.printchar(" ") + ios.printhex(wert,2) + ios.printchar(" ") + ios.printchar("[") + repeat wert>>3 + ios.printqchar("‣") + repeat (255-wert)>>3 + ios.printqchar(" ") + ios.printchar("]") + ios.printnl + +PRI print_port(pnr,wert) + + ios.print(string("Port ")) + ios.printdec(pnr) + ios.printchar(" ") + + repeat 8 + if wert & 1 + ios.printqchar("‣") + else + ios.printqchar(" ") + wert := wert >> 1 + ios.printnl + + +DAT + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} diff --git a/source/sid/1startrk.dmp b/source/sid/1startrk.dmp new file mode 100644 index 0000000..21c1036 Binary files /dev/null and b/source/sid/1startrk.dmp differ diff --git a/source/sid/2startrk.dmp b/source/sid/2startrk.dmp new file mode 100644 index 0000000..683fc7b Binary files /dev/null and b/source/sid/2startrk.dmp differ diff --git a/source/sid/Yie_Ar_Kung_Fu.dmp b/source/sid/Yie_Ar_Kung_Fu.dmp new file mode 100644 index 0000000..d0388a4 Binary files /dev/null and b/source/sid/Yie_Ar_Kung_Fu.dmp differ diff --git a/source/sid/boing.sid b/source/sid/boing.sid new file mode 100644 index 0000000..1439267 Binary files /dev/null and b/source/sid/boing.sid differ diff --git a/source/sid/triborg.sid b/source/sid/triborg.sid new file mode 100644 index 0000000..bc43cb0 Binary files /dev/null and b/source/sid/triborg.sid differ diff --git a/source/triborg/triborg-bel.spin b/source/triborg/triborg-bel.spin new file mode 100644 index 0000000..c67e49c --- /dev/null +++ b/source/triborg/triborg-bel.spin @@ -0,0 +1,3098 @@ +{{ GR0KEY +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Ingo Kripahle │ +│ Copyright (c) 2010 Ingo Kripahle │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : drohne235@googlemail.com +System : Hive +Name : GRAPHICS-KEYBOARD +Chip : Bellatrix +Typ : Treiber +Version : 00 +Subversion : 01 +Funktion : Graphics + Keyboard + +Dieser Bellatrix-Code stellt Regnatix alle Graphics- und Keyboard-Funktionen +zur Verfügung. Der Speicher für den PASM-Code im hRAM wird nach dem Start der +Cogs als Heap verwendet. + +Logbuch : + +11-11-2011-dr235 - erste funktionsfähige version erstellt +23-11-2011-dr235 - keyboard-objekt in root-objekt eingefügt + - keyboard-pasm-code zu heap hinzugefügt + + + + + +}} +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 +_STACK = ($3000 + $3000 + 100) >> 2 + + +' +---------- +' | +------- system +' | | +---- version (änderungen) +' | | | +- subversion (hinzufügungen) +CHIP_VER = $00_01_01_01 + +CHIP_SPEC = gcon#b_tv|gcon#b_key|gcon#b_vec + +' hbeat --------+ +' clk -------+| +' /wr ------+|| +' /hs -----+||| +------------------------- /cs +' |||| | -------- d0..d7 +DB_IN = %00001001_00000000_00000000_00000000 'maske: dbus-eingabe +DB_OUT = %00001001_00000000_00000000_11111111 'maske: dbus-ausgabe + +M1 = %00000010_00000000_00000000_00000000 +M2 = %00000010_10000000_00000000_00000000 'busclk=1? & /cs=0? + +M3 = %00000000_00000000_00000000_00000000 +M4 = %00000010_00000000_00000000_00000000 'busclk=0? + +x_tiles = 16 +y_tiles = 12 + +paramcount = 14 +bit_base = $2000 +disp_base = $5000 + +max_x = x_tiles * 16 +max_y = y_tiles * 16 + +OBJ + + tv : "bel-tv" + gcon : "glob-con" 'globale konstanten + +VAR + + long bel_key 'letzter tastencode + long datadr 'adresse des heap + + long tv_status '0/1/2 = off/visible/invisible read-only + long tv_enable '0/? = off/on write-only + long tv_pins '%ppmmm = pins write-only + long tv_mode '%ccinp = chroma,interlace,ntsc/pal,swap write-only + long tv_screen 'pointer to screen (words) write-only + long tv_colors 'pointer to colors (longs) write-only + long tv_hc 'horizontal cells write-only + long tv_vc 'vertical cells write-only + long tv_hx 'horizontal cell expansion write-only + long tv_vx 'vertical cell expansion write-only + long tv_ho 'horizontal offset write-only + long tv_vo 'vertical offset write-only + long tv_broadcast 'broadcast frequency (Hz) write-only + long tv_auralcog 'aural fm cog write-only + + word screen[x_tiles * y_tiles] 'tilemap + long grcolors[64] 'farbregister + +CON ''------------------------------------------------- BELLATRIX + +PUB main | cmd,i,index 'chip: kommandointerpreter +''funktionsgruppe : chip +''funktion : kommandointerpreter +''eingabe : - +''ausgabe : - + + init_subsysteme 'bus/vga/keyboard/maus initialisieren + repeat + i := 0 + cmd := gc 'kommando empfangen + case cmd +' ---------------------------------------------- KEYBOARD + 1: key_stat '1: Tastaturstatus senden + 2: key_code '2: Tastaturzeichen senden + 4: key_spec '4: Statustasten ($100..$1FF) abfragen +' ---------------------------------------------- GRAPHICS + 'clear + 10: clear + 'copy(dest_ptr) + 11: copy(disp_base) + 'color(c) + 12: color(gc) + 'width(w) + 13: width(gc) + 'colorwidth(c, w) + 14: colorwidth(gc,gc) + 'plot(x, y) + 15: plot(gc,gc) + 'line(x, y) + 16: line(gc,gc) + 'arc(x, y, xr, yr, angle, anglestep, steps, arcmode) + 17: arc(gc,gc,gc,gc,gw,gw,gc,gc) + 'vec(x, y, vecscale, vecangle, vecdef_ptr) + 18: vec(gc,gc,gc,gw,datadr+gw) + 'vecarc(x, y, xr, yr, angle, vecscale, vecangle, vecdef_ptr) + 19: vecarc(gc,gc,gc,gc,gw,gc,gw,datadr+gw) + 'pix(x, y, pixrot, pixdef_ptr) + 20: pix(gc,gc,gc,datadr+gw) + 'pixarc(x, y, xr, yr, angle, pixrot, pixdef_ptr) + 21: pixarc(gc,gc,gc,gc,gw,gc,datadr+gw) + 'text(x, y, string_ptr) + 22: text(gc,gc,datadr+gw) + 'textarc(x, y, xr, yr, angle, string_ptr) + 23: textarc(gc,gc,gc,gc,gw,datadr+gw) + 'textmode(x_scale, y_scale, spacing, justification) + 24: textmode(gc,gc,gc,gc) + 'box(x, y, box_width, box_height) + 25: box(gc,gc,gc,gc) + 'quad(x1, y1, x2, y2, x3, y3, x4, y4) + 26: quad(gc,gc,gc,gc,gc,gc,gc,gc) + 'tri(x1, y1, x2, y2, x3, y3) + 27: tri(gc,gc,gc,gc,gc,gc) +' ---------------------------------------------- CHIP-MANAGMENT + 93: repeat 64 'colortab empfangen + grcolors[i++] := gl + 94: repeat x_tiles * y_tiles 'screen empfangen + screen[i++] := gw + 95: index := gw + repeat gw 'heap empfangen + byte[datadr+index+i++] := gc + 96: pw(@grdatend-datadr) 'heapgrösse senden + 97: setup(tv_hc, tv_vc, 0, 0, bit_base) 'dynamischer modus + 98: setup(tv_hc, tv_vc, 0, 0, disp_base) 'statischer modus + 99: reboot 'bellatrix neu starten + +PUB init_subsysteme | i,tx,ty 'chip: initialisierung des bellatrix-chips +''funktionsgruppe : chip +''funktion : - initialisierung des businterface +'' : - vga & keyboard-treiber starten +''eingabe : - +''ausgabe : - + + dira := db_in 'datenbus auf eingabe schalten + outa[gcon#bus_hs] := 1 'handshake inaktiv + keystart(gcon#b_keybd, gcon#b_keybc) 'tastaturport starten + + 'tv-treiber starten + longmove(@tv_status, @tvparams, paramcount) + tv_screen := @screen + tv_colors := @grcolors + tv.start(@tv_status) + + 'start and setup graphics + grstart +' setup(tv_hc, tv_vc, 0, 0, disp_base) 'bitmap_base = puffer in welchen gezeichnet wird +' clear + + datadr := (@grdat+4) & $FFFD 'ausgerichtete datenadresse berechnen + + +PUB pc(zeichen) 'chip: ein byte an regnatix senden +''funktionsgruppe : chip +''funktion : ein byte an regnatix senden +''eingabe : byte +''ausgabe : - + + waitpeq(M1,M2,0) 'busclk=1? & prop2=0? + dira := db_out 'datenbus auf ausgabe stellen + outa[7..0] := zeichen 'daten ausgeben + outa[gcon#bus_hs] := 0 'daten gültig + waitpeq(M3,M4,0) 'busclk=0? + dira := db_in 'bus freigeben + outa[gcon#bus_hs] := 1 'daten ungültig + +PUB gc : zeichen 'chip: ein byte von regnatix empfangen +''funktionsgruppe : chip +''funktion : ein byte von regnatix empfangen +''eingabe : - +''ausgabe : byte + + waitpeq(M1,M2,0) 'busclk=1? & prop2=0? + zeichen := ina[7..0] 'daten einlesen + outa[gcon#bus_hs] := 0 'daten quittieren + waitpeq(M3,M4,0) 'busclk=0? + outa[gcon#bus_hs] := 1 + + + +CON ''------------------------------------------------- SUBPROTOKOLL-FUNKTIONEN + +PUB pw(wert) 'sub: word senden +''funktionsgruppe : sub +''funktion : subprotokoll um einen long-wert an regnatix zu senden +''eingabe : 16bit wert der gesendet werden soll +''ausgabe : - +''busprotokoll : [put.byte1][put.byte2] +'' : [ hsb ][ ] + + pc(wert >> 8) + pc(wert) + +PUB gw:wert 'sub: word empfangen +''funktionsgruppe : sub +''funktion : subprotokoll um einen 16bit-wert von regnatix zu empfangen +''eingabe : - +''ausgabe : 16bit-wert der empfangen wurde +''busprotokoll : [get.byte1][get.byte2] +'' : [ hsb ][ lsb ] + + wert := gc << 8 + wert := wert + gc + +PUB gl:wert 'sub: long empfangen +''funktionsgruppe : sub +''funktion : subprotokoll um einen long-wert von regnatix zu empfangen +''eingabe : - +''ausgabe : 32bit-wert der empfangen wurde +''busprotokoll : [get.byte1][get.byte2][get.byte3][get.byte4] +'' : [ hsb ][ ][ ][ lsb ] + + wert := gc << 24 '32 bit empfangen hsb/lsb + wert := wert + gc << 16 + wert := wert + gc << 8 + wert := wert + gc + +CON ''------------------------------------------------- KEYBOARD-FUNKTIONEN + +PUB key_stat 'key: tastaturstatus abfragen + + pc(gotkey) + +PUB key_code 'key: tastencode abfragen + + bel_key := key + case bel_key + $c8: bel_key := $08 'backspace wandeln + pc(bel_key) + +PUB key_spec 'key: statustaten vom letzten tastencode abfragen + + pc(bel_key >> 8) + +DAT ''tv-parameter + +tvparams long 0 'status + long 1 'enable + long %010_0101 'pins New Board + long %0000 'mode +pscreen long 0 'screen +pcolors long 0 'colors + long x_tiles 'hc - horizontale tiles + long y_tiles 'vc - vertikale tiles + long 10 'hx + long 1 'vx + long 0 'ho + long 0 'vo + long 60_000_000 '_xinfreq<<4 'broadcast + long 0 'auralcog + +CON ' Keyboard-Objekt +''*************************************** +''* PS/2 Keyboard Driver v1.0.1 * +''* Author: Chip Gracey * +''* Copyright (c) 2004 Parallax, Inc. * +''* See end of file for terms of use. * +''*************************************** + +{-----------------REVISION HISTORY--------------------------------- + v1.0.1 - Updated 6/15/2006 to work with Propeller Tool 0.96 + ------------------------------------------------------------------} + +{-----------------KEYBOARD LAYOUT HISTORY-------------------------- + 2009-08-31 (Y-M-D) + Patch for german keyboard layout + Author: oog + Added german keyboard layout. + Original layout is commented as keyboard-us-en (US-English). + German layout is commented as keyboard-de (de = deutsch = "german"). + + Now there are two tables for keys with and without SHIFT-Key. + It should be easier to implement different international layouts. + However, it's bigger now and uses more memory. + + 2009-09-05 (Y-M-D) + Fixed bugs + - code bug on home-key fixed + new replace-codes for de_ae, de_ou and de_ue + + New + - Documentation of control-key bits + This should be helpful for translatíons of this driver into + different languages. + - table_alt_r + This table contains characters for the german "AltGr" key. + - AltGr+F1..F12 + Returns line-characters, selected from $90..$9f + + 2009-09-06 (Y-M-D) + Fixed bugs + - patch table_shift for "?" + + Differences to Parallax driver: + - Different codes for NumLock, CapsLock and ScrLock to avoid + conflict with german "ß" + Codes are defined as constants and easy to change + - Easy Cursor codes implemented to avoit conflict with the "Ä"-key + Easy Cursor codes are easy to understand, + for example "Cursor Left" is the character "←" + + ------------------------------------------------------------------} + +CON + de_ae = $A6 'replace code - not used on keyboard + de_oe = $A7 'replace code - not used on keyboard + de_ue = $A8 'replace code - not used on keyboard + lock = $BC 'Parallax used codes $DD, $DE and $DF + 'There was a conflict between $DF=NumLock="ß" + ScrLk = lock + CpsLk = lock+1 + NumLk = lock+2 + +' +'Uncomment one of the next constant blocks +' +' + +{{Parallax cursor codes start}} +{{ + CrsLt = $C0E4 + CrsRt = $C1E6 + CrsUp = $C2E8 + CrsDn = $C3E2 + CrsHm = $C4E7 'Conflict with key "Ä" ($C4) + CrsEn = $C5E1 + PgUp = $C6E9 + PgDn = $C7E3 + Bksp = $00C8 + Del = $C9EA + Ins = $CAE0 + Esc = $00CB + Apps = $CC00 + Power = $CD00 + Sleep = $CE00 + WkUp = $CF00 +}} +{{Parallax cursor codes end}} + + +{{Easy cursor codes start}} + + CrsLt = $02E4 '← + CrsRt = $03E6 '→ + CrsUp = $04E8 '↑ + CrsDn = $05E2 '↓ + CrsHm = $06E7 '◀ + CrsEn = $07E1 '▶ + PgUp = $A0E9 ' + PgDn = $A2E3 ' + Bksp = $00C8 'È + Del = $BAEA ' + Ins = $BBE0 ' + Esc = $001B ' + Apps = $CC00 'Ì + Power = $CD00 'Í + Sleep = $CE00 'Î + WkUp = $CF00 'Ï + +{{Easy cursor codes end}} + +VAR + + long cog + + long par_tail 'key buffer tail read/write (19 contiguous longs) + long par_head 'key buffer head read-only + long par_present 'keyboard present read-only + long par_states[8] 'key states (256 bits) read-only + long par_keys[8] 'key buffer (16 words) read-only (also used to pass initial parameters) + + +PUB keystart(dpin, cpin) : okay + +'' Start keyboard driver - starts a cog +'' returns false if no cog available +'' +'' dpin = data signal on PS/2 jack +'' cpin = clock signal on PS/2 jack +'' +'' use 100-ohm resistors between pins and jack +'' use 10K-ohm resistors to pull jack-side signals to VDD +'' connect jack-power to 5V, jack-gnd to VSS +'' +'' all lock-keys will be enabled, NumLock will be initially 'on', +'' and auto-repeat will be set to 15cps with a delay of .5s + + okay := startx(dpin, cpin, %0_000_000, %01_01000) + + +PUB startx(dpin, cpin, locks, auto) : okay + +'' Like start, but allows you to specify lock settings and auto-repeat +'' +'' locks = lock setup +'' bit 6 disallows shift-alphas (case set soley by CapsLock) +'' bits 5..3 disallow toggle of NumLock/CapsLock/ScrollLock state +'' bits 2..0 specify initial state of NumLock/CapsLock/ScrollLock +'' (eg. %0_001_100 = disallow ScrollLock, NumLock initially 'on') +'' +'' auto = auto-repeat setup +'' bits 6..5 specify delay (0=.25s, 1=.5s, 2=.75s, 3=1s) +'' bits 4..0 specify repeat rate (0=30cps..31=2cps) +'' (eg %01_00000 = .5s delay, 30cps repeat) + + longmove(@par_keys, @dpin, 4) + okay := cog := cognew(@entry, @par_tail) + 1 + + + +PUB present : truefalse + +'' Check if keyboard present - valid ~2s after start +'' returns t|f + + truefalse := -par_present + + +PUB key : keycode + +'' Get key (never waits) +'' returns key (0 if buffer empty) + + if par_tail <> par_head + keycode := par_keys.word[par_tail] + par_tail := ++par_tail & $F + + +PUB getkey : keycode + +'' Get next key (may wait for keypress) +'' returns key + + repeat until (keycode := key) + + +PUB newkey : keycode + +'' Clear buffer and get new key (always waits for keypress) +'' returns key + + par_tail := par_head + keycode := getkey + + +PUB gotkey : truefalse + +'' Check if any key in buffer +'' returns t|f + + truefalse := par_tail <> par_head + + +PUB clearkeys + +'' Clear key buffer + + par_tail := par_head + + +PUB keystate(k) : state + +'' Get the state of a particular key +'' returns t|f + + state := -(par_states[k >> 5] >> k & 1) + +CON ' Graphics-Objekt + +''*************************************** +''* Graphics Driver v1.0 * +''* Author: Chip Gracey * +''* Copyright (c) 2005 Parallax, Inc. * +''* See end of file for terms of use. * +''*************************************** + +'' +'' Theory of Operation: +'' +'' A cog is launched which processes commands via the PUB routines. +'' +'' Points, lines, arcs, sprites, text, and polygons are rasterized into +'' a specified stretch of memory which serves as a generic bitmap buffer. +'' +'' The bitmap can be displayed by the TV.SRC or VGA.SRC driver. +'' +'' See GRAPHICS_DEMO.SRC for usage example. +'' + +CON + + #1, _setup, _color, _width, _plot, _line, _arc, _vec, _vecarc, _pix, _pixarc, _text, _textarc, _textmode, _fill, _loop + +VAR + + long command + + long bitmap_base 'bitmap data + long bitmap_longs + word bases[32] + + long pixel_width 'pixel data + long slices[8] + + long text_xs, text_ys, text_sp, text_just 'text data (these 4 must be contiguous) + + +PUB grstart : okay + +'' Start graphics driver - starts a cog +'' returns false if no cog available + + fontptr := @font 'set font pointer (same for all instances) + cognew(@loop, @command) + 1 + +PUB setup(xtiles, ytiles, x_origin, y_origin, base_ptr) | bases_ptr, slices_ptr + +'' Set bitmap parameters +'' +'' xtiles - number of x tiles (tiles are 16x16 pixels each) +'' ytiles - number of y tiles +'' x_origin - relative-x center pixel +'' y_origin - relative-y center pixel +'' base_ptr - base address of bitmap + + setcommand(_loop, 0) 'make sure last command finished + + repeat bases_ptr from 0 to xtiles - 1 <# 31 'write bases + bases[bases_ptr] := base_ptr + bases_ptr * ytiles << 6 + + ytiles <<= 4 'adjust arguments and do setup command + y_origin := ytiles - y_origin - 1 + bases_ptr := @bases + slices_ptr := @slices + setcommand(_setup, @xtiles) + + bitmap_base := base_ptr 'retain high-level bitmap data + bitmap_longs := xtiles * ytiles + + +PUB clear + +'' Clear bitmap + + setcommand(_loop, 0) 'make sure last command finished + + longfill(bitmap_base, 0, bitmap_longs) 'clear bitmap + + +PUB copy(dest_ptr) + +'' Copy bitmap +'' use for double-buffered display (flicker-free) +'' +'' dest_ptr - base address of destination bitmap + + setcommand(_loop, 0) 'make sure last command finished + + longmove(dest_ptr, bitmap_base, bitmap_longs) 'copy bitmap + + +PUB color(c) + +'' Set pixel color to two-bit pattern +'' +'' c - color code in bits[1..0] + + setcommand(_color, @colors[c & 3]) 'set color + + +PUB width(w) | pixel_passes, r, i, p + +'' Set pixel width +'' actual width is w[3..0] + 1 +'' +'' w - 0..15 for round pixels, 16..31 for square pixels + + r := not w & $10 'determine pixel shape/width + w &= $F + pixel_width := w + pixel_passes := w >> 1 + 1 + + setcommand(_width, @w) 'do width command now to avoid updating slices when busy + + p := w ^ $F 'update slices to new shape/width + repeat i from 0 to w >> 1 + slices[i] := true >> (p << 1) << (p & $E) + if r and pixels[w] & |< i + p += 2 + if r and i == pixel_passes - 2 + p += 2 + + +PUB colorwidth(c, w) + +'' Set pixel color and width + + color(c) + width(w) + + +PUB plot(gx, gy) + +'' Plot point +'' +'' x,y - point + + setcommand(_plot, @gx) + + +PUB line(gx, gy) + +'' Draw a line to point +'' +'' x,y - endpoint + + setcommand(_line, @gx) + + +PUB arc(gx, gy, xr, yr, angle, anglestep, steps, arcmode) + +'' Draw an arc +'' +'' x,y - center of arc +'' xr,yr - radii of arc +'' angle - initial angle in bits[12..0] (0..$1FFF = 0°..359.956°) +'' anglestep - angle step in bits[12..0] +'' steps - number of steps (0 just leaves (x,y) at initial arc position) +'' arcmode - 0: plot point(s) +'' 1: line to point(s) +'' 2: line between points +'' 3: line from point(s) to center + + setcommand(_arc, @gx) + + +PUB vec(gx, gy, vecscale, vecangle, vecdef_ptr) + +'' Draw a vector sprite +'' +'' x,y - center of vector sprite +'' vecscale - scale of vector sprite ($100 = 1x) +'' vecangle - rotation angle of vector sprite in bits[12..0] +'' vecdef_ptr - address of vector sprite definition +'' +'' +'' Vector sprite definition: +'' +'' word $8000|$4000+angle 'vector mode + 13-bit angle (mode: $4000=plot, $8000=line) +'' word length 'vector length +'' ... 'more vectors +'' ... +'' word 0 'end of definition + + setcommand(_vec, @gx) + + +PUB vecarc(gx, gy, xr, yr, angle, vecscale, vecangle, vecdef_ptr) + +'' Draw a vector sprite at an arc position +'' +'' x,y - center of arc +'' xr,yr - radii of arc +'' angle - angle in bits[12..0] (0..$1FFF = 0°..359.956°) +'' vecscale - scale of vector sprite ($100 = 1x) +'' vecangle - rotation angle of vector sprite in bits[12..0] +'' vecdef_ptr - address of vector sprite definition + + setcommand(_vecarc, @gx) + + +PUB pix(gx, gy, pixrot, pixdef_ptr) + +'' Draw a pixel sprite +'' +'' x,y - center of vector sprite +'' pixrot - 0: 0°, 1: 90°, 2: 180°, 3: 270°, +4: mirror +'' pixdef_ptr - address of pixel sprite definition +'' +'' +'' Pixel sprite definition: +'' +'' word 'word align, express dimensions and center, define pixels +'' byte xwords, ywords, xorigin, yorigin +'' word %%xxxxxxxx,%%xxxxxxxx +'' word %%xxxxxxxx,%%xxxxxxxx +'' word %%xxxxxxxx,%%xxxxxxxx +'' ... + + setcommand(_pix, @gx) + + +PUB pixarc(gx, gy, xr, yr, angle, pixrot, pixdef_ptr) + +'' Draw a pixel sprite at an arc position +'' +'' x,y - center of arc +'' xr,yr - radii of arc +'' angle - angle in bits[12..0] (0..$1FFF = 0°..359.956°) +'' pixrot - 0: 0°, 1: 90°, 2: 180°, 3: 270°, +4: mirror +'' pixdef_ptr - address of pixel sprite definition + + setcommand(_pixarc, @gx) + + +PUB text(gx, gy, string_ptr) | justx, justy + +'' Draw text +'' +'' x,y - text position (see textmode for sizing and justification) +'' string_ptr - address of zero-terminated string (it may be necessary to call .finish +'' immediately afterwards to prevent subsequent code from clobbering the +'' string as it is being drawn + + justify(string_ptr, @justx) 'justify string and draw text + setcommand(_text, @gx) + + +PUB textarc(gx, gy, xr, yr, angle, string_ptr) | justx, justy + +'' Draw text at an arc position +'' +'' x,y - center of arc +'' xr,yr - radii of arc +'' angle - angle in bits[12..0] (0..$1FFF = 0°..359.956°) +'' string_ptr - address of zero-terminated string (it may be necessary to call .finish +'' immediately afterwards to prevent subsequent code from clobbering the +'' string as it is being drawn + + justify(string_ptr, @justx) 'justify string and draw text + setcommand(_textarc, @gx) + + +PUB textmode(x_scale, y_scale, spacing, justification) + +'' Set text size and justification +'' +'' x_scale - x character scale, should be 1+ +'' y_scale - y character scale, should be 1+ +'' spacing - character spacing, 6 is normal +'' justification - bits[1..0]: 0..3 = left, center, right, left +'' bits[3..2]: 0..3 = bottom, center, top, bottom + + longmove(@text_xs, @x_scale, 4) 'retain high-level text data + + setcommand(_textmode, @x_scale) 'set text mode + + +PUB box(gx, gy, box_width, box_height) | x2, y2, pmin, pmax + +'' Draw a box with round/square corners, according to pixel width +'' +'' x,y - box left, box bottom + + if box_width > pixel_width and box_height > pixel_width + + pmax := pixel_width - (pmin := pixel_width >> 1) 'get pixel-half-min and pixel-half-max + + gx += pmin 'adjust coordinates to accomodate width + gy += pmin + x2 := gx + box_width - 1 - pixel_width + y2 := gy + box_height - 1 - pixel_width + + plot(gx, gy) 'plot round/square corners + plot(gx, y2) + plot(x2, gy) + plot(x2, y2) + + fill(gx, y2 + pmax, 0, (x2 - gx) << 16, 0, 0, pmax) 'fill gaps + fill(gx, y, 0, (x2 - gx) << 16, 0, 0, pmin) + fill(gx - pmin, y2, 0, (x2 - gx + pixel_width) << 16, 0, 0, y2 - gy) + + +PUB quad(x1, y1, x2, y2, x3, y3, x4, y4) + +'' Draw a solid quadrilateral +'' vertices must be ordered clockwise or counter-clockwise + + tri(x1, y1, x2, y2, x3, y3) 'draw two triangle to make 4-sides polygon + tri(x3, y3, x4, y4, x1, y1) + + +PUB tri(x1, y1, x2, y2, x3, y3) | xy[2] + +'' Draw a solid triangle + +' reorder vertices by descending y + + case (y1 => y2) & %100 | (y2 => y3) & %010 | (y1 => y3) & %001 + %000: + longmove(@xy, @x1, 2) + longmove(@x1, @x3, 2) + longmove(@x3, @xy, 2) + %010: + longmove(@xy, @x1, 2) + longmove(@x1, @x2, 4) + longmove(@x3, @xy, 2) + %011: + longmove(@xy, @x1, 2) + longmove(@x1, @x2, 2) + longmove(@x2, @xy, 2) + %100: + longmove(@xy, @x3, 2) + longmove(@x2, @x1, 4) + longmove(@x1, @xy, 2) + %101: + longmove(@xy, @x2, 2) + longmove(@x2, @x3, 2) + longmove(@x3, @xy, 2) + +' draw triangle + + fill(x1, y1, (x3 - x1) << 16 / (y1 - y3 + 1), (x2 - x1) << 16 / (y1 - y2 + 1), (x3 - x2) << 16 / (y2 - y3 + 1), y1 - y2, y1 - y3) + + +PUB finish + +'' Wait for any current graphics command to finish +'' use this to insure that it is safe to manually manipulate the bitmap + + setcommand(_loop, 0) 'make sure last command finished + + +PRI fill(gx, gy, da, db, db2, linechange, lines_minus_1) + + setcommand(_fill, @gx) + + +PRI justify(string_ptr, justptr) | gx + + gx := (strsize(string_ptr) - 1) * text_xs * text_sp + text_xs * 5 - 1 + long[justptr] := -lookupz(text_just >> 2 & 3: 0, gx >> 1, gx, 0) + long[justptr][1] := -lookupz(text_just & 3: 0, text_ys << 3, text_ys << 4, 0) + + +PRI setcommand(cmd, argptr) + + command := cmd << 16 + argptr 'write command and pointer + repeat while command 'wait for command to be cleared, signifying receipt + + +CON + + ' Vector font primitives + + xa0 = %000 << 0 'x line start / arc center + xa1 = %001 << 0 + xa2 = %010 << 0 + xa3 = %011 << 0 + xa4 = %100 << 0 + xa5 = %101 << 0 + xa6 = %110 << 0 + xa7 = %111 << 0 + + ya0 = %0000 << 3 'y line start / arc center + ya1 = %0001 << 3 + ya2 = %0010 << 3 + ya3 = %0011 << 3 + ya4 = %0100 << 3 + ya5 = %0101 << 3 + ya6 = %0110 << 3 + ya7 = %0111 << 3 + ya8 = %1000 << 3 + ya9 = %1001 << 3 + yaA = %1010 << 3 + yaB = %1011 << 3 + yaC = %1100 << 3 + yaD = %1101 << 3 + yaE = %1110 << 3 + yaF = %1111 << 3 + + xb0 = %000 << 7 'x line end + xb1 = %001 << 7 + xb2 = %010 << 7 + xb3 = %011 << 7 + xb4 = %100 << 7 + xb5 = %101 << 7 + xb6 = %110 << 7 + xb7 = %111 << 7 + + yb0 = %0000 << 10 'y line end + yb1 = %0001 << 10 + yb2 = %0010 << 10 + yb3 = %0011 << 10 + yb4 = %0100 << 10 + yb5 = %0101 << 10 + yb6 = %0110 << 10 + yb7 = %0111 << 10 + yb8 = %1000 << 10 + yb9 = %1001 << 10 + ybA = %1010 << 10 + ybB = %1011 << 10 + ybC = %1100 << 10 + ybD = %1101 << 10 + ybE = %1110 << 10 + ybF = %1111 << 10 + + ax1 = %0 << 7 'x arc radius + ax2 = %1 << 7 + + ay1 = %00 << 8 'y arc radius + ay2 = %01 << 8 + ay3 = %10 << 8 + ay4 = %11 << 8 + + a0 = %0000 << 10 'arc start/length + a1 = %0001 << 10 'bits[1..0] = start (0..3 = 0°, 90°, 180°, 270°) + a2 = %0010 << 10 'bits[3..2] = length (0..3 = 360°, 270°, 180°, 90°) + a3 = %0011 << 10 + a4 = %0100 << 10 + a5 = %0101 << 10 + a6 = %0110 << 10 + a7 = %0111 << 10 + a8 = %1000 << 10 + a9 = %1001 << 10 + aA = %1010 << 10 + aB = %1011 << 10 + aC = %1100 << 10 + aD = %1101 << 10 + aE = %1110 << 10 + aF = %1111 << 10 + + fline = %0 << 14 'line command + farc = %1 << 14 'arc command + + more = %1 << 15 'another arc/line + + +DAT + +' Color codes + +colors long %%0000000000000000 + long %%1111111111111111 + long %%2222222222222222 + long %%3333333333333333 + +' Round pixel recipes + +pixels byte %00000000,%00000000,%00000000,%00000000 '0,1,2,3 + byte %00000000,%00000000,%00000010,%00000101 '4,5,6,7 + byte %00001010,%00001010,%00011010,%00011010 '8,9,A,B + byte %00110100,%00111010,%01110100,%01110100 'C,D,E,F + +' Vector font - standard ascii characters ($21-$7E) + +font word fline + xa2 + yaC + xb2 + yb7 + more '! + word fline + xa2 + ya5 + xb2 + yb4 + + word fline + xa1 + yaD + xb1 + ybC + more '" + word fline + xa3 + yaD + xb3 + ybC + + word fline + xa1 + yaA + xb1 + yb6 + more '# + word fline + xa3 + yaA + xb3 + yb6 + more + word fline + xa0 + ya9 + xb4 + yb9 + more + word fline + xa0 + ya7 + xb4 + yb7 + + word farc + xa2 + ya9 + a9 + ax2 + ay1 + more '$ + word farc + xa2 + ya7 + aB + ax2 + ay1 + more + word fline + xa0 + ya6 + xb2 + yb6 + more + word fline + xa2 + yaA + xb4 + ybA + more + word fline + xa2 + yaA + xb2 + ybB + more + word fline + xa2 + ya6 + xb2 + yb5 + + word farc + xa1 + yaA + a0 + ax1 + ay1 + more '% + word farc + xa3 + ya6 + a0 + ax1 + ay1 + more + word fline + xa0 + ya6 + xb4 + ybA + + word farc + xa2 + yaA + a7 + ax1 + ay1 + more '& + word farc + xa2 + ya7 + a5 + ax2 + ay2 + more + word fline + xa1 + yaA + xb4 + yb5 + + word fline + xa2 + yaD + xb2 + ybC ' ' + + word farc + xa3 + ya9 + aD + ax1 + ay4 + more '( + word farc + xa3 + ya7 + aE + ax1 + ay4 + more + word fline + xa2 + ya7 + xb2 + yb9 + + word farc + xa1 + ya9 + aC + ax1 + ay4 + more ') + word farc + xa1 + ya7 + aF + ax1 + ay4 + more + word fline + xa2 + ya7 + xb2 + yb9 + + word fline + xa4 + ya6 + xb0 + ybA + more '* + word fline + xa0 + ya6 + xb4 + ybA + more + word fline + xa2 + yaB + xb2 + yb5 + + word fline + xa0 + ya8 + xb4 + yb8 + more '+ + word fline + xa2 + yaA + xb2 + yb6 + + word fline + xa2 + ya4 + xb1 + yb3 ', + + word fline + xa0 + ya8 + xb4 + yb8 '- + + word fline + xa2 + ya5 + xb2 + yb4 '. + + word fline + xa0 + ya4 + xb4 + ybC '/ + + word farc + xa2 + ya8 + a0 + ax2 + ay4 '0 + + word fline + xa0 + ya4 + xb4 + yb4 + more '1 + word fline + xa2 + ya4 + xb2 + ybC + more + word fline + xa0 + yaA + xb2 + ybC + + word farc + xa2 + yaA + a8 + ax2 + ay2 + more '2 + word farc + xa2 + yaA + aF + ax2 + ay3 + more + word farc + xa2 + ya4 + aD + ax2 + ay3 + more + word fline + xa0 + ya4 + xb4 + yb4 + + word farc + xa2 + yaA + a7 + ax2 + ay2 + more '3 + word farc + xa2 + ya6 + a6 + ax2 + ay2 + + word fline + xa2 + yaC + xb0 + yb7 + more '4 + word fline + xa0 + ya7 + xb4 + yb7 + more + word fline + xa3 + ya4 + xb3 + yb8 + + word farc + xa2 + ya6 + aB + ax2 + ay2 + more '5 + word fline + xa4 + yaC + xb0 + ybC + more + word fline + xa0 + yaC + xb0 + yb8 + more + word fline + xa0 + ya8 + xb2 + yb8 + more + word fline + xa0 + ya4 + xb2 + yb4 + + word farc + xa2 + ya6 + a0 + ax2 + ay2 + more '6 + word farc + xa2 + ya8 + aD + ax2 + ay4 + more + word fline + xa0 + ya6 + xb0 + yb8 + more + word fline + xa2 + yaC + xb3 + ybC + + word fline + xa0 + yaC + xb4 + ybC + more '7 + word fline + xa1 + ya4 + xb4 + ybC + + word farc + xa2 + ya6 + a0 + ax2 + ay2 + more '8 + word farc + xa2 + yaA + a0 + ax2 + ay2 + + word farc + xa2 + yaA + a0 + ax2 + ay2 + more '9 + word farc + xa2 + ya8 + aF + ax2 + ay4 + more + word fline + xa4 + ya8 + xb4 + ybA + more + word fline + xa1 + ya4 + xb2 + yb4 + + word fline + xa2 + ya6 + xb2 + yb7 + more ': + word fline + xa2 + yaA + xb2 + yb9 + + word fline + xa2 + ya4 + xb1 + yb3 + more '; + word fline + xa2 + ya8 + xb2 + yb7 + + word fline + xa0 + ya8 + xb4 + ybA + more '< + word fline + xa0 + ya8 + xb4 + yb6 + + word fline + xa0 + yaA + xb4 + ybA + more '= + word fline + xa0 + ya6 + xb4 + yb6 + + word fline + xa4 + ya8 + xb0 + ybA + more '> + word fline + xa4 + ya8 + xb0 + yb6 + + word farc + xa2 + yaB + a8 + ax2 + ay1 + more '? + word farc + xa3 + yaB + aF + ax1 + ay2 + more + word farc + xa3 + ya7 + aD + ax1 + ay2 + more + word fline + xa2 + ya5 + xb2 + yb4 + + word farc + xa2 + ya8 + a0 + ax1 + ay1 + more '@ + word farc + xa2 + ya8 + a4 + ax2 + ay3 + more + word farc + xa3 + ya8 + aF + ax1 + ay1 + more + word farc + xa2 + ya6 + aF + ax2 + ay1 + more + word fline + xa3 + ya7 + xb3 + yb9 + + word farc + xa2 + yaA + a8 + ax2 + ay2 + more 'A + word fline + xa0 + ya4 + xb0 + ybA + more + word fline + xa4 + ya4 + xb4 + ybA + more + word fline + xa0 + ya8 + xb4 + yb8 + + word farc + xa2 + yaA + aB + ax2 + ay2 + more 'B + word farc + xa2 + ya6 + aB + ax2 + ay2 + more + word fline + xa0 + ya4 + xb0 + ybC + more + word fline + xa0 + ya4 + xb2 + yb4 + more + word fline + xa0 + ya8 + xb2 + yb8 + more + word fline + xa0 + yaC + xb2 + ybC + + word farc + xa2 + yaA + a8 + ax2 + ay2 + more 'C + word farc + xa2 + ya6 + aA + ax2 + ay2 + more + word fline + xa0 + ya6 + xb0 + ybA + + word farc + xa2 + yaA + aC + ax2 + ay2 + more 'D + word farc + xa2 + ya6 + aF + ax2 + ay2 + more + word fline + xa0 + ya4 + xb0 + ybC + more + word fline + xa4 + ya6 + xb4 + ybA + more + word fline + xa0 + ya4 + xb2 + yb4 + more + word fline + xa0 + yaC + xb2 + ybC + + word fline + xa0 + ya4 + xb0 + ybC + more 'E + word fline + xa0 + ya4 + xb4 + yb4 + more + word fline + xa0 + ya8 + xb3 + yb8 + more + word fline + xa0 + yaC + xb4 + ybC + + word fline + xa0 + ya4 + xb0 + ybC + more 'F + word fline + xa0 + ya8 + xb3 + yb8 + more + word fline + xa0 + yaC + xb4 + ybC + + word farc + xa2 + yaA + a8 + ax2 + ay2 + more 'G + word farc + xa2 + ya6 + aA + ax2 + ay2 + more + word fline + xa0 + ya6 + xb0 + ybA + more + word fline + xa4 + ya4 + xb4 + yb7 + more + word fline + xa3 + ya7 + xb4 + yb7 + + word fline + xa0 + ya4 + xb0 + ybC + more 'H + word fline + xa4 + ya4 + xb4 + ybC + more + word fline + xa0 + ya8 + xb4 + yb8 + + word fline + xa2 + ya4 + xb2 + ybC + more 'I + word fline + xa0 + ya4 + xb4 + yb4 + more + word fline + xa0 + yaC + xb4 + ybC + + word farc + xa2 + ya6 + aA + ax2 + ay2 + more 'J + word fline + xa4 + ya6 + xb4 + ybC + + word fline + xa0 + ya4 + xb0 + ybC + more 'K + word fline + xa4 + yaC + xb0 + yb8 + more + word fline + xa4 + ya4 + xb0 + yb8 + + word fline + xa0 + ya4 + xb0 + ybC + more 'L + word fline + xa0 + ya4 + xb4 + yb4 + + word fline + xa0 + ya4 + xb0 + ybC + more 'M + word fline + xa4 + ya4 + xb4 + ybC + more + word fline + xa2 + ya8 + xb0 + ybC + more + word fline + xa2 + ya8 + xb4 + ybC + + word fline + xa0 + ya4 + xb0 + ybC + more 'N + word fline + xa4 + ya4 + xb4 + ybC + more + word fline + xa4 + ya4 + xb0 + ybC + + word farc + xa2 + yaA + a8 + ax2 + ay2 + more '0 + word farc + xa2 + ya6 + aA + ax2 + ay2 + more + word fline + xa0 + ya6 + xb0 + ybA + more + word fline + xa4 + ya6 + xb4 + ybA + + word farc + xa2 + yaA + aB + ax2 + ay2 + more 'P + word fline + xa0 + ya4 + xb0 + ybC + more + word fline + xa0 + ya8 + xb2 + yb8 + more + word fline + xa0 + yaC + xb2 + ybC + + word farc + xa2 + yaA + a8 + ax2 + ay2 + more 'Q + word farc + xa2 + ya6 + aA + ax2 + ay2 + more + word fline + xa0 + ya6 + xb0 + ybA + more + word fline + xa4 + ya6 + xb4 + ybA + more + word fline + xa2 + ya6 + xb4 + yb3 + + word farc + xa2 + yaA + aB + ax2 + ay2 + more 'R + word fline + xa0 + ya4 + xb0 + ybC + more + word fline + xa0 + ya8 + xb2 + yb8 + more + word fline + xa0 + yaC + xb2 + ybC + more + word fline + xa4 + ya4 + xb2 + yb8 + + word farc + xa2 + yaA + a4 + ax2 + ay2 + more 'S + word farc + xa2 + ya6 + a6 + ax2 + ay2 + + word fline + xa2 + ya4 + xb2 + ybC + more 'T + word fline + xa0 + yaC + xb4 + ybC + + word farc + xa2 + ya6 + aA + ax2 + ay2 + more 'U + word fline + xa0 + ya6 + xb0 + ybC + more + word fline + xa4 + ya6 + xb4 + ybC + + word fline + xa2 + ya4 + xb0 + ybC + more 'V + word fline + xa2 + ya4 + xb4 + ybC + + word fline + xa0 + yaC + xb0 + yb4 + more 'W + word fline + xa4 + yaC + xb4 + yb4 + more + word fline + xa2 + ya8 + xb0 + yb4 + more + word fline + xa2 + ya8 + xb4 + yb4 + + word fline + xa4 + ya4 + xb0 + ybC + more 'X + word fline + xa0 + ya4 + xb4 + ybC + + word fline + xa0 + yaC + xb2 + yb8 + more 'Y + word fline + xa4 + yaC + xb2 + yb8 + more + word fline + xa2 + ya4 + xb2 + yb8 + + word fline + xa0 + yaC + xb4 + ybC + more 'Z + word fline + xa0 + ya4 + xb4 + ybC + more + word fline + xa0 + ya4 + xb4 + yb4 + + word fline + xa2 + yaD + xb2 + yb3 + more '[ + word fline + xa2 + yaD + xb4 + ybD + more + word fline + xa2 + ya3 + xb4 + yb3 + + word fline + xa4 + ya4 + xb0 + ybC '\ + + word fline + xa2 + yaD + xb2 + yb3 + more '[ + word fline + xa2 + yaD + xb0 + ybD + more + word fline + xa2 + ya3 + xb0 + yb3 + + word fline + xa2 + yaA + xb0 + yb6 + more '^ + word fline + xa2 + yaA + xb4 + yb6 + + word fline + xa0 + ya1 + xa4 + yb1 '_ + + word fline + xa1 + ya9 + xb3 + yb7 '` + + word farc + xa2 + ya6 + a0 + ax2 + ay2 + more 'a + word fline + xa4 + ya4 + xb4 + yb8 + + word farc + xa2 + ya6 + a0 + ax2 + ay2 + more 'b + word fline + xa0 + ya4 + xb0 + ybC + + word farc + xa2 + ya6 + a9 + ax2 + ay2 + more 'c + word fline + xa2 + ya4 + xb4 + yb4 + more + word fline + xa2 + ya8 + xb4 + yb8 + + word farc + xa2 + ya6 + a0 + ax2 + ay2 + more 'd + word fline + xa4 + ya4 + xb4 + ybC + + word farc + xa2 + ya6 + a4 + ax2 + ay2 + more 'e + word fline + xa0 + ya6 + xb4 + yb6 + more + word fline + xa2 + ya4 + xb4 + yb4 + + word farc + xa4 + yaA + aD + ax2 + ay2 + more 'f + word fline + xa0 + ya8 + xb4 + yb8 + more + word fline + xa2 + ya4 + xb2 + ybA + + word farc + xa2 + ya6 + a0 + ax2 + ay2 + more 'g + word farc + xa2 + ya3 + aF + ax2 + ay2 + more + word fline + xa4 + ya3 + xb4 + yb8 + more + word fline + xa1 + ya1 + xb2 + yb1 + + word farc + xa2 + ya6 + a8 + ax2 + ay2 + more 'h + word fline + xa0 + ya4 + xb0 + ybC + more + word fline + xa4 + ya4 + xb4 + yb6 + + word fline + xa1 + ya4 + xb3 + yb4 + more 'i + word fline + xa2 + ya4 + xb2 + yb8 + more + word fline + xa1 + ya8 + xb2 + yb8 + more + word fline + xa2 + yaB + xb2 + ybA + + word farc + xa0 + ya3 + aF + ax2 + ay2 + more 'j + word fline + xa2 + ya3 + xb2 + yb8 + more + word fline + xa1 + ya8 + xb2 + yb8 + more + word fline + xa2 + yaB + xb2 + ybA + + word fline + xa0 + ya4 + xb0 + ybC + more 'k + word fline + xa0 + ya6 + xb2 + yb6 + more + word fline + xa2 + ya6 + xb4 + yb8 + more + word fline + xa2 + ya6 + xb4 + yb4 + + word fline + xa1 + ya4 + xb3 + yb4 + more 'l + word fline + xa2 + ya4 + xb2 + ybC + more + word fline + xa1 + yaC + xb2 + ybC + + word farc + xa1 + ya7 + a8 + ax1 + ay1 + more 'm + word farc + xa3 + ya7 + a8 + ax1 + ay1 + more + word fline + xa0 + ya4 + xb0 + yb8 + more + word fline + xa2 + ya4 + xb2 + yb7 + more + word fline + xa4 + ya4 + xb4 + yb7 + + word farc + xa2 + ya6 + a8 + ax2 + ay2 + more 'n + word fline + xa0 + ya4 + xb0 + yb8 + more + word fline + xa4 + ya4 + xb4 + yb6 + + word farc + xa2 + ya6 + a0 + ax2 + ay2 'o + + word farc + xa2 + ya6 + a0 + ax2 + ay2 + more 'p + word fline + xa0 + ya1 + xb0 + yb8 + + word farc + xa2 + ya6 + a0 + ax2 + ay2 + more 'q + word fline + xa4 + ya1 + xb4 + yb8 + + word farc + xa2 + ya7 + a8 + ax2 + ay1 + more 'r + word fline + xa0 + ya4 + xb0 + yb8 + + word farc + xa2 + ya7 + a9 + ax2 + ay1 + more 's + word farc + xa2 + ya5 + aB + ax2 + ay1 + more + word fline + xa0 + ya4 + xb2 + yb4 + more + word fline + xa2 + ya8 + xb4 + yb8 + + word farc + xa4 + ya6 + aE + ax2 + ay2 + more 't + word fline + xa0 + ya8 + xb4 + yb8 + more + word fline + xa2 + ya6 + xb2 + ybA + + word farc + xa2 + ya6 + aA + ax2 + ay2 + more 'u + word fline + xa0 + ya6 + xb0 + yb8 + more + word fline + xa4 + ya4 + xb4 + yb8 + + word fline + xa0 + ya8 + xb2 + yb4 + more 'v + word fline + xa4 + ya8 + xb2 + yb4 + + word farc + xa1 + ya5 + aA + ax1 + ay1 + more 'w + word farc + xa3 + ya5 + aA + ax1 + ay1 + more + word fline + xa0 + ya5 + xb0 + yb8 + more + word fline + xa2 + ya5 + xb2 + yb6 + more + word fline + xa4 + ya5 + xb4 + yb8 + + word fline + xa0 + ya8 + xb4 + yb4 + more 'x + word fline + xa0 + ya4 + xb4 + yb8 + + word farc + xa2 + ya6 + aA + ax2 + ay2 + more 'y + word farc + xa2 + ya3 + aF + ax2 + ay2 + more + word fline + xa4 + ya3 + xb4 + yb8 + more + word fline + xa0 + ya6 + xb0 + yb8 + more + word fline + xa1 + ya1 + xb2 + yb1 + + word fline + xa0 + ya8 + xb4 + yb8 + more 'z + word fline + xa4 + ya8 + xb0 + yb4 + more + word fline + xa0 + ya4 + xb4 + yb4 + + word farc + xa3 + yaA + aD + ax1 + ay3 + more '{ + word farc + xa1 + ya6 + aC + ax1 + ay2 + more + word farc + xa1 + yaA + aF + ax1 + ay2 + more + word farc + xa3 + ya6 + aE + ax1 + ay3 + + word fline + xa2 + ya3 + xb2 + ybD '| + + word farc + xa1 + yaA + aC + ax1 + ay3 + more '} + word farc + xa3 + ya6 + aD + ax1 + ay2 + more + word farc + xa3 + yaA + aE + ax1 + ay2 + more + word farc + xa1 + ya6 + aF + ax1 + ay3 + + word farc + xa1 + ya8 + a8 + ax1 + ay1 + more '~ + word farc + xa3 + ya8 + aA + ax1 + ay1 + +' Vector font - custom characters ($7F+) + + word fline + xa2 + ya9 + xb0 + yb4 + more 'delta + word fline + xa2 + ya9 + xb4 + yb4 + more + word fline + xa0 + ya4 + xb4 + yb4 + + word farc + xa2 + ya7 + a8 + ax2 + ay2 + more 'omega + word farc + xa1 + ya7 + aE + ax1 + ay2 + more + word farc + xa3 + ya7 + aF + ax1 + ay2 + more + word fline + xa1 + ya5 + xb1 + yb4 + more + word fline + xa3 + ya5 + xb3 + yb4 + more + word fline + xa0 + ya4 + xb1 + yb4 + more + word fline + xa4 + ya4 + xb3 + yb4 + + word farc + xa2 + ya8 + a0 + ax1 + ay1 'bullet + +CON fx = 3 'number of custom characters + +CON ''------------------------------------------------- GRAPHICS-HEAP +' +' diese daten werden zur laufzeit nur wärend des systemstarts gebraucht +' nach dem start steht dieser bereich bis zum screenpuffer als +' dynamischer speicher für strings, vektorobjekte und sprites zur verfügung +' +DAT ' graphics-heap-start (temp. pasm-puffer) + +grdat + +DAT ' keyboard-pasm-code (wird nach start als heap genutzt) + +'****************************************** +'* Assembly language PS/2 keyboard driver * +'****************************************** + + org +' +' +' Entry +' +entry movd :par,#_dpin 'load input parameters _dpin/_cpin/_locks/_auto + mov x,par + add x,#11*4 + mov y,#4 +:par rdlong 0,x + add :par,dlsb + add x,#4 + djnz y,#:par + + mov dmask,#1 'set pin masks + shl dmask,_dpin + mov cmask,#1 + shl cmask,_cpin + + test _dpin,#$20 wc 'modify port registers within code + muxc _d1,dlsb + muxc _d2,dlsb + muxc _d3,#1 + muxc _d4,#1 + test _cpin,#$20 wc + muxc _c1,dlsb + muxc _c2,dlsb + muxc _c3,#1 + + mov _head,#0 'reset output parameter _head +' +' +' Reset keyboard +' +reset mov dira,#0 'reset directions + mov dirb,#0 + + movd :par,#_present 'reset output parameters _present/_states[8] + mov x,#1+8 +:par mov 0,#0 + add :par,dlsb + djnz x,#:par + + mov stat,#8 'set reset flag +' +' +' Update parameters +' +update movd :par,#_head 'update output parameters _head/_present/_states[8] + mov x,par + add x,#1*4 + mov y,#1+1+8 +:par wrlong 0,x + add :par,dlsb + add x,#4 + djnz y,#:par + + test stat,#8 wc 'if reset flag, transmit reset command + if_c mov data,#$FF + if_c call #transmit +' +' +' Get scancode +' +newcode mov stat,#0 'reset state + +:same call #receive 'receive byte from keyboard + + cmp data,#$83+1 wc 'scancode? + + if_nc cmp data,#$AA wz 'powerup/reset? + if_nc_and_z jmp #configure + + if_nc cmp data,#$E0 wz 'extended? + if_nc_and_z or stat,#1 + if_nc_and_z jmp #:same + + if_nc cmp data,#$F0 wz 'released? + if_nc_and_z or stat,#2 + if_nc_and_z jmp #:same + + if_nc jmp #newcode 'unknown, ignore +' +' +' Translate scancode and enter into buffer +' + test stat,#1 wc 'lookup code with extended flag + rcl data,#1 + mov data_s,data 'keyboard-de: store scancode for next table lookup with shift + call #look + + cmp data,#0 wz 'if unknown, ignore + if_z jmp #newcode + + mov t,_states+6 'remember lock keys in _states + + mov x,data 'set/clear key bit in _states + shr x,#5 + add x,#_states + movd :reg,x + mov y,#1 + shl y,data + test stat,#2 wc +:reg muxnc 0,y + + if_nc cmpsub data,#$F0 wc 'if released or shift/ctrl/alt/win, done + if_c jmp #update + + mov y,_states+7 'get shift/ctrl/alt/win bit pairs + shr y,#16 + + cmpsub data,#$E0 wc 'translate keypad, considering numlock + if_c test _locks,#%100 wz + if_c_and_z add data,#@keypad1-@table + if_c_and_nz add data,#@keypad2-@table + if_c call #look + if_c jmp #:flags + + 'for keyboard-de changed #$DD to #lock + 'in next code segment + + cmpsub data,#lock wc 'handle scrlock/capslock/numlock + if_c mov x,#%001_000 + if_c shl x,data + if_c andn x,_locks + if_c shr x,#3 + if_c shr t,#29 'ignore auto-repeat + if_c andn x,t wz + if_c xor _locks,x + if_c add data,#lock + if_c_and_nz or stat,#4 'if change, set configure flag to update leds + +{{ for keyboard-us-en start }} +{{ + + test y,#%11 wz 'get shift into nz +' +'Translate scan-codes $5B..$60 with characters from table "shift1" +' + if_nz cmp data,#$60+1 wc 'check shift1 + if_nz_and_c cmpsub data,#$5B wc + if_nz_and_c add data,#@shift1-@table + if_nz_and_c call #look + if_nz_and_c andn y,#%11 + +' +'Translate scan-codes $27..$3D with characters from table "shift2" +' + if_nz cmp data,#$3D+1 wc 'check shift2 + if_nz_and_c cmpsub data,#$27 wc + if_nz_and_c add data,#@shift2-@table + if_nz_and_c call #look + if_nz_and_c andn y,#%11 + + test _locks,#%010 wc 'check shift-alpha, considering capslock + muxnc :shift,#$20 + test _locks,#$40 wc + if_nz_and_nc xor :shift,#$20 + cmp data,#"z"+1 wc + if_c cmpsub data,#"a" wc +:shift if_c add data,#"A" + if_c andn y,#%11 +}} +{{ for keyboard-us-en end }} + +{{ for keyboard-de start }} + + cmp data,#de_ae wz 'replace ae + if_z mov data,#"ä" + cmp data,#de_oe wz 'replace oe + if_z mov data,#"ö" + cmp data,#de_ue wz 'replace ue + if_z mov data,#"ü" + +' +'Documentation of control-key bits +' +' test y,#%00000011 wz 'get SHIFT into nz +' test y,#%00000100 wz 'get CTRL-L into nz +' test y,#%00001000 wz 'get CTRL-R into nz +' test y,#%00010000 wz 'get ALT-L into nz +' test y,#%00100000 wz 'get ALT-R into nz +' test y,#%01000000 wz 'get WIN-L into nz +' test y,#%10000000 wz 'get WIN-R into nz + + +' +'Translate scan-codes with characters from "table_shift" +' + + test y,#%00000011 wz 'get shift into nz + test _locks,#$40 wc + if_nz_and_nc mov data,data_s 'reload scancode + if_nz_and_nc call #look_shift 'translate by table_shift + + +' +'Translate scan-codes with characters from "table_alt_r" +' + + test y,#%00100000 wz 'get ALT-R (AltGr) into nz + if_nz mov data,data_s 'reload scancode + if_nz call #look_alt_r 'translate by table_alt_r + + +{{ for keyboard-de end }} + + +:flags ror data,#8 'add shift/ctrl/alt/win flags + mov x,#4 '+$100 if shift +:loop test y,#%11 wz '+$200 if ctrl + shr y,#2 '+$400 if alt + if_nz or data,#1 '+$800 if win + ror data,#1 + djnz x,#:loop + rol data,#12 + + rdlong x,par 'if room in buffer and key valid, enter + sub x,#1 + and x,#$F + cmp x,_head wz + if_nz test data,#$FF wz + if_nz mov x,par + if_nz add x,#11*4 + if_nz add x,_head + if_nz add x,_head + if_nz wrword data,x + if_nz add _head,#1 + if_nz and _head,#$F + + test stat,#4 wc 'if not configure flag, done + if_nc jmp #update 'else configure to update leds +' +' +' Configure keyboard +' +configure mov data,#$F3 'set keyboard auto-repeat + call #transmit + mov data,_auto + and data,#%11_11111 + call #transmit + + mov data,#$ED 'set keyboard lock-leds + call #transmit + mov data,_locks + rev data,#-3 & $1F + test data,#%100 wc + rcl data,#1 + and data,#%111 + call #transmit + + mov x,_locks 'insert locks into _states + and x,#%111 + shl _states+7,#3 + or _states+7,x + ror _states+7,#3 + + mov _present,#1 'set _present + + jmp #update 'done + +{{ for keyboard-de start }} +' +' Lookup byte in table_shift +' +look_shift ror data,#2 'perform lookup + movs :reg,data + add :reg,#table_shift + shr data,#27 + mov x,data +:reg mov data,0 + shr data,x + and data,#$FF 'isolate byte +look_shift_ret ret + +' +' Lookup byte in table_alt_r +' +look_alt_r ror data,#2 'perform lookup + movs :reg,data + add :reg,#table_alt_r + shr data,#27 + mov x,data +:reg mov data,0 + shr data,x + and data,#$FF 'isolate byte +look_alt_r_ret ret + +{{ for keyboard-de end }} + +' +' +' Lookup byte in table +' +look ror data,#2 'perform lookup + movs :reg,data + add :reg,#table + shr data,#27 + mov x,data +:reg mov data,0 + shr data,x + + jmp #rand 'isolate byte +' +' +' Transmit byte to keyboard +' +transmit +_c1 or dira,cmask 'pull clock low + movs napshr,#13 'hold clock for ~128us (must be >100us) + call #nap +_d1 or dira,dmask 'pull data low + movs napshr,#18 'hold data for ~4us + call #nap +_c2 xor dira,cmask 'release clock + + test data,#$0FF wc 'append parity and stop bits to byte + muxnc data,#$100 + or data,dlsb + + mov x,#10 'ready 10 bits +transmit_bit call #wait_c0 'wait until clock low + shr data,#1 wc 'output data bit +_d2 muxnc dira,dmask + mov wcond,c1 'wait until clock high + call #wait + djnz x,#transmit_bit 'another bit? + + mov wcond,c0d0 'wait until clock and data low + call #wait + mov wcond,c1d1 'wait until clock and data high + call #wait + + call #receive_ack 'receive ack byte with timed wait + cmp data,#$FA wz 'if ack error, reset keyboard + if_nz jmp #reset + +transmit_ret ret +' +' +' Receive byte from keyboard +' +receive test _cpin,#$20 wc 'wait indefinitely for initial clock low + waitpne cmask,cmask +receive_ack + mov x,#11 'ready 11 bits +receive_bit call #wait_c0 'wait until clock low + movs napshr,#16 'pause ~16us + call #nap +_d3 test dmask,ina wc 'input data bit + rcr data,#1 + mov wcond,c1 'wait until clock high + call #wait + djnz x,#receive_bit 'another bit? + + shr data,#22 'align byte + test data,#$1FF wc 'if parity error, reset keyboard + if_nc jmp #reset +rand and data,#$FF 'isolate byte + +look_ret +receive_ack_ret +receive_ret ret +' +' +' Wait for clock/data to be in required state(s) +' +wait_c0 mov wcond,c0 '(wait until clock low) + +wait mov y,tenms 'set timeout to 10ms + +wloop movs napshr,#18 'nap ~4us + call #nap +_c3 test cmask,ina wc 'check required state(s) +_d4 test dmask,ina wz 'loop until got state(s) or timeout +wcond if_never djnz y,#wloop '(replaced with c0/c1/c0d0/c1d1) + + tjz y,#reset 'if timeout, reset keyboard +wait_ret +wait_c0_ret ret + + +c0 if_c djnz y,#wloop '(if_never replacements) +c1 if_nc djnz y,#wloop +c0d0 if_c_or_nz djnz y,#wloop +c1d1 if_nc_or_z djnz y,#wloop +' +' +' Nap +' +nap rdlong t,#0 'get clkfreq +napshr shr t,#18/16/13 'shr scales time + min t,#3 'ensure waitcnt won't snag + add t,cnt 'add cnt to time + waitcnt t,#0 'wait until time elapses (nap) + +nap_ret ret +' +' +' Initialized data +' +' +dlsb long 1 << 9 +tenms long 10_000 / 4 +' +' +' Lookup table +' ascii scan extkey regkey ()=keypad +' + +{{keyboard-us-en start}} +{{ +table + ' + '$00 --- F9 --- F5 F3 F1 F2 F12 + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$00D8,$0000,$00D4,$00D2,$00D0,$00D1,$00DB + + ' + '$08 --- F10 F8 F6 F4 TAB ` --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$00D9,$00D7,$00D5,$00D3,$0009,$0060,$0000 + + ' ALT-R Left CTRL-R + '$10 --- ALT-L SHIFT --- CTRL_L q 1 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$F5F4,$00F0,$0000,$F3F2,$0071,$0031,$0000 + + ' WIN-L + '$18 --- --- z s a w 2 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$007A,$0073,$0061,$0077,$0032,$F600 + + ' WIN-R + '$20 --- c x d e 4 3 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0063,$0078,$0064,$0065,$0034,$0033,$F700 + + ' Apps + '$28 --- Spc v f t r 5 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0020,$0076,$0066,$0074,$0072,$0035,$CC00 + + ' Power + '$30 --- n b h g y 6 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$006E,$0062,$0068,$0067,$0079,$0036,$CD00 + + ' Sleep + '$38 --- --- m j u 7 8 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$006D,$006A,$0075,$0037,$0038,$CE00 + + ' + '$40 --- , k i o 0 9 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$002C,$006B,$0069,$006F,$0030,$0039,$0000 + + ' (/) + '$48 --- . / l } p + --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$002E,$EF2F,$006C,$003B,$0070,$002D,$0000 + + ' + '$50 --- --- { --- [ = --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0027,$0000,$005B,$003D,$0000,$0000 + + ' CAPS Right (ENTER) Wk.up + '$58 LOCK SHIFT ENTER ] --- \ --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $00DE,$00F1,$EB0D,$005D,$0000,$005C,$CF00,$0000 + + ' + '$60 --- --- --- --- --- --- BkSpc --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0000,$0000,$0000,$0000,$00C8,$0000 + + ' End Left Home + '$68 --- (1) --- (4) (7) --- --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$C5E1,$0000,$C0E4,$C4E7,$0000,$0000,$0000 + + ' Ins Del Down --- Right Up + '$70 (0) (.) (2) (5) (6) (8) Esc NumLock + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $CAE0,$C9EA,$C3E2,$00E5,$C1E6,$C2E8,$00CB,$00DF + + ' PgDn PrScr PgUp + '$78 F11 (+) (3) (-) (*) (9) ScrLock --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $00DA,$00EC,$C7E3,$00ED,$DCEE,$C6E9,$00DD,$0000 + + ' + '$80 --- --- --- F7 + ' ===== ===== ===== ===== + word $0000,$0000,$0000,$00D6 + + +keypad1 byte $CA, $C5, $C3, $C7, $C0, 0, $C1, $C4, $C2, $C6, $C9, $0D, "+-*/" + +keypad2 byte "0123456789.", $0D, "+-*/" + +' +'Table "shift1" for scan-codes $5B..$60 +' +shift1 byte "{|}", 0, 0, "~" + +' +'Table "shift1" for scan-codes $27..$3D +' +shift2 byte $22, 0, 0, 0, 0, "<_>?)!@#$%^&*(", 0, ":", 0, "+" +}} +{{keyboard-us-en end}} + + +{{keyboard-de start}} + +table + ' + '$00 --- F9 --- F5 F3 F1 F2 F12 + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$00D8,$0000,$00D4,$00D2,$00D0,$00D1,$00DB + + ' + '$08 --- F10 F8 F6 F4 TAB _^_ --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$00D9,$00D7,$00D5,$00D3,$0009,$005E,$0000 + + ' ALT-R Left CTRL-R + '$10 --- ALT-L SHIFT --- CTRL_L q 1 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$F5F4,$00F0,$0000,$F3F2,$0071,$0031,$0000 + + ' WIN-L + '$18 --- --- _y_ s a w 2 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0079,$0073,$0061,$0077,$0032,$F600 + + ' WIN-R + '$20 --- c x d e 4 3 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0063,$0078,$0064,$0065,$0034,$0033,$F700 + + ' Apps + '$28 --- Spc v f t r 5 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0020,$0076,$0066,$0074,$0072,$0035,Apps + + ' Power + '$30 --- n b h g _z_ 6 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$006E,$0062,$0068,$0067,$007A,$0036,Power + + ' Sleep + '$38 --- --- m j u 7 8 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$006D,$006A,$0075,$0037,$0038,Sleep + + ' + '$40 --- , k i o 0 9 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$002C,$006B,$0069,$006F,$0030,$0039,$0000 + + ' (/) + '$48 --- . _-_ l _oe_ p _sz_ --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$002E,$EF2D,$006C,de_oe,$0070,$00DF,$0000 + + ' + '$50 --- --- _ae_ --- _ue_ _'_ --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,de_ae,$0000,de_ue,$0060,$0000,$0000 + + ' CAPS Right (ENTER) Wk.up + '$58 LOCK SHIFT ENTER _+_ --- # --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word CpsLk,$00F1,$EB0D,$002B,$0000,$0023,WkUp ,$0000 + + ' + '$60 --- _<_ --- --- --- --- BkSpc --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$003C,$0000,$0000,$0000,$0000,BkSp ,$0000 + + ' End Left Home + '$68 --- (1) --- (4) (7) --- --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,CrsEn,$0000,CrsLt,CrsHm,$0000,$0000,$0000 + + ' Ins Del Down --- Right Up + '$70 (0) (.) (2) (5) (6) (8) Esc NumLock + ' ===== ===== ===== ===== ===== ===== ===== ===== + word Ins , Del ,CrsDn,$00E5,CrsRt,CrsUp, Esc ,NumLk + + ' PgDn PrScr PgUp + '$78 F11 (+) (3) (-) (*) (9) ScrLock --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $00DA,$00EC,PgDn ,$00ED,$DCEE,PgUp ,ScrLk,$0000 + + ' + '$80 --- --- --- F7 + ' ===== ===== ===== ===== + word $0000,$0000,$0000,$00D6 + + +keypad1 byte $CA, $C5, $C3, $C7, $C0, 0, $C1, $C4, $C2, $C6, $C9, $0D, "+-*/" + +keypad2 byte "0123456789.", $0D, "+-*/" + + +table_shift + ' + '$00 --- F9 --- F5 F3 F1 F2 F12 + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$00D8,$0000,$00D4,$00D2,$00D0,$00D1,$00DB + + ' + '$08 --- F10 F8 F6 F4 TAB _°_ --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$00D9,$00D7,$00D5,$00D3,$0009,$00B0,$0000 + + ' ALT-R Left CTRL-R + '$10 --- ALT-L SHIFT --- CTRL_L Q ! --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$F5F4,$00F0,$0000,$F3F2,$0051,$0021,$0000 + + ' WIN-L + '$18 --- --- _Y_ S A W " --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0059,$0053,$0041,$0057,$0022,$F600 + + ' WIN-R + '$20 --- C X D E $ SHF+3 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0043,$0058,$0044,$0045,$0024,$0014,$F700 + + ' Apps + '$28 --- Spc V F T R % --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0020,$0056,$0046,$0054,$0052,$0025,Apps + + ' Power + '$30 --- N B H G _Z_ & --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$004E,$0042,$0048,$0047,$005A,$0026,Power + + ' Sleep + '$38 --- --- M J U / ( --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$004D,$004A,$0055,$002F,$0028,Sleep + + ' + '$40 --- ; K I O _=_ ) --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$003B,$004B,$0049,$004F,$003D,$0029,$0000 + + ' (/) + '$48 --- : ___ L _OE_ P _sz_ --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$003A,$EF5F,$004C,$00D6,$0050,$003F,$0000 + + ' + '$50 --- --- _AE_ --- _UE_ _'_ --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$00C4,$0000,$00DC,$0060,$0000,$0000 + + ' CAPS Right (ENTER) Wk.up + '$58 LOCK SHIFT ENTER _*_ --- _'_ --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word CpsLk,$00F1,$EB0D,$002A,$0000,$0027,WkUp ,$0000 + + ' + '$60 --- _>_ --- --- --- --- BkSpc --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$003E,$0000,$0000,$0000,$0000,BkSp ,$0000 + + ' End Left Home + '$68 --- (1) --- (4) (7) --- --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,CrsEn,$0000,CrsLt,CrsHm,$0000,$0000,$0000 + + ' Ins Del Down --- Right Up + '$70 (0) (.) (2) (5) (6) (8) Esc NumLock + ' ===== ===== ===== ===== ===== ===== ===== ===== + word Ins , Del ,CrsDn,$00E5,CrsRt,CrsUp, Esc ,NumLk + + ' PgDn PrScr PgUp + '$78 F11 (+) (3) (-) (*) (9) ScrLock --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $00DA,$00EC,PgDn ,$00ED,$DCEE,PgUp ,ScrLk,$0000 + + ' + '$80 --- --- --- F7 + ' ===== ===== ===== ===== + word $0000,$0000,$0000,$00D6 + + + +table_alt_r + ' + '$00 --- F9 --- F5 F3 F1 F2 F12 + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0097,$0000,$0090,$009D,$009F,$009E,$0094 + + ' + '$08 --- F10 F8 F6 F4 TAB _^_ --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0096,$0093,$0091,$009C,$0009,$0000,$0000 + + ' ALT-R Left CTRL-R + '$10 --- ALT-L SHIFT --- CTRL_L q 1 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$F5F4,$00F0,$0000,$F3F2, "@", "¹", $0000 + + ' WIN-L + '$18 --- --- _y_ s a w 2 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0000,$0000,$0000,$0000, "²", $F600 + + ' WIN-R + '$20 --- c x d e 4 3 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0000,$0000, "€", $0000, "³", $F700 + + ' Apps + '$28 --- Spc v f t r 5 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0000,$0000,$0000,$0000,$0000,Apps + + ' Power + '$30 --- n b h g _z_ 6 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0000,$0000,$0000,$0000,$0000,Power + + ' Sleep + '$38 --- --- m j u 7 8 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000, "µ", $0000,$0000, "{" , "[" ,Sleep + + ' + '$40 --- , k i o 0 9 --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0000,$0000,$0000, "}", "]", $0000 + + ' (/) + '$48 --- . _-_ l _oe_ p _sz_ --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0000,$0000,$0000,$0000, "\", $0000 + + ' + '$50 --- --- _ae_ --- _ue_ _'_ --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000 + + ' CAPS Right (ENTER) Wk.up + '$58 LOCK SHIFT ENTER _+_ --- # --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word CpsLk,$00F1,$EB0D, "~", $0000,$0000,WkUp ,$0000 + + ' + '$60 --- _<_ --- --- --- --- BkSpc --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000, "|", $0000,$0000,$0000,$0000,BkSp ,$0000 + + ' End Left Home + '$68 --- (1) --- (4) (7) --- --- --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0000,CrsEn,$0000,CrsLt,CrsHm,$0000,$0000,$0000 + + ' Ins Del Down --- Right Up + '$70 (0) (.) (2) (5) (6) (8) Esc NumLock + ' ===== ===== ===== ===== ===== ===== ===== ===== + word Ins , Del ,CrsDn,$00E5,CrsRt,CrsUp, Esc ,NumLk + + ' PgDn PrScr PgUp + '$78 F11 (+) (3) (-) (*) (9) ScrLock --- + ' ===== ===== ===== ===== ===== ===== ===== ===== + word $0095,$00EC,PgDn ,$00ED,$DCEE,PgUp ,ScrLk,$0000 + + ' + '$80 --- --- --- F7 + ' ===== ===== ===== ===== + word $0000,$0000,$0000,$0092 + + +{{keyboard-de end}} + +' +' +' Uninitialized data +' +dmask res 1 +cmask res 1 +stat res 1 +data res 1 +data_s res 1 'Scancode-Storage (for keyboard-de) +x res 1 +y res 1 +t res 1 + +_head res 1 'write-only +_present res 1 'write-only +_states res 8 'write-only +_dpin res 1 'read-only at start +_cpin res 1 'read-only at start +_locks res 1 'read-only at start +_auto res 1 'read-only at start + +'' +'' +'' _________ +'' Key Codes +'' +'' 00..DF = keypress and keystate +'' E0..FF = keystate only +'' +'' +'' 09 Tab +'' 0D Enter +'' 20 Space +'' 21 ! +'' 22 " +'' 23 # +'' 24 $ +'' 25 % +'' 26 & +'' 27 ' +'' 28 ( +'' 29 ) +'' 2A * +'' 2B + +'' 2C , +'' 2D - +'' 2E . +'' 2F / +'' 30 0..9 +'' 3A : +'' 3B ; +'' 3C < +'' 3D = +'' 3E > +'' 3F ? +'' 40 @ +'' 41..5A A..Z +'' 5B [ +'' 5C \ +'' 5D ] +'' 5E ^ +'' 5F _ +'' 60 ` +'' 61..7A a..z +'' 7B { +'' 7C | +'' 7D } +'' 7E ~ +'' +'' 80-BF (future international character support) +'' +'' C0 Left Arrow +'' C1 Right Arrow +'' C2 Up Arrow +'' C3 Down Arrow +'' C4 Home +'' C5 End +'' C6 Page Up +'' C7 Page Down +'' C8 Backspace +'' C9 Delete +'' CA Insert +'' CB Esc +'' CC Apps +'' CD Power +'' CE Sleep +'' CF Wakeup +'' +'' D0..DB F1..F12 +'' DC Print Screen +'' DD Scroll Lock +'' DE Caps Lock +'' DF Num Lock +'' +'' E0..E9 Keypad 0..9 +'' EA Keypad . +'' EB Keypad Enter +'' EC Keypad + +'' ED Keypad - +'' EE Keypad * +'' EF Keypad / +'' +'' F0 Left Shift +'' F1 Right Shift +'' F2 Left Ctrl +'' F3 Right Ctrl +'' F4 Left Alt +'' F5 Right Alt +'' F6 Left Win +'' F7 Right Win +'' +'' FD Scroll Lock State +'' FE Caps Lock State +'' FF Num Lock State +'' +'' +100 if Shift +'' +200 if Ctrl +'' +400 if Alt +'' +800 if Win +'' +'' eg. Ctrl-Alt-Delete = $6C9 +'' +'' +'' Note: Driver will buffer up to 15 keystrokes, then ignore overflow. + +DAT ' graphics-pasm-code (wird nach start als heap genutzt) + +'************************************* +'* Assembly language graphics driver * +'************************************* + + org +' +' +' Graphics driver - main loop +' +loop rdlong t1,par wz 'wait for command + if_z jmp #loop + + movd :arg,#arg0 'get 8 arguments + mov t2,t1 + mov t3,#8 +:arg rdlong arg0,t2 + add :arg,d0 + add t2,#4 + djnz t3,#:arg + + wrlong zero,par 'zero command to signify received + + call #setd 'set dx,dy from arg0,arg1 + + ror t1,#16+2 'lookup command address + add t1,#jumps + movs :table,t1 + rol t1,#2 + shl t1,#3 +:table mov t2,0 + shr t2,t1 + and t2,#$FF + jmp t2 'jump to command + + +jumps byte 0 '0 + byte setup_ '1 + byte color_ '2 + byte width_ '3 + byte plot_ '4 + byte line_ '5 + byte arc_ '6 + byte vec_ '7 + byte vecarc_ '8 + byte pix_ '9 + byte pixarc_ 'A + byte text_ 'B + byte textarc_ 'C + byte textmode_ 'D + byte fill_ 'E + byte loop 'F +' +' +' setup(x_tiles, y_tiles*16, x_origin, y_origin, base_ptr) bases_ptr, slices_ptr +' +setup_ mov xlongs,arg0 'set xlongs, ylongs + mov ylongs,arg1 + mov xorigin,arg2 'set xorigin, yorigin + mov yorigin,arg3 + mov basesptr,arg5 'set pointers + mov slicesptr,arg6 + + jmp #loop +' +' +' color(c) +' +color_ mov pcolor,arg0 'set pixel color + + jmp #loop +' +' +' width(w) pixel_passes +' +width_ mov pwidth,arg0 'set pixel width + mov passes,arg1 'set pixel passes + + jmp #loop +' +' +' plot(x, y) +' +plot_ call #plotd + + jmp #loop +' +' +' line(x, y) +' +line_ call #linepd + + jmp #loop +' +' +' arc(x, y, xr, yr, angle, anglestep, iterations, mode) +' +arc_ and arg7,#3 'limit mode + +:loop call #arca 'get arc dx,dy + + cmp arg7,#1 wz 'if not mode 1, set px,py + if_nz mov px,dx + if_nz mov py,dy + + tjz arg6,#loop 'if no points exit with new px,py + + cmp arg7,#3 wz 'if mode 3, set center + if_z call #setd + + test arg7,#1 wz 'if mode 0 or 2, plot point + if_z call #plotp + + test arg7,#1 wz 'if mode 1 or 3, plot line + if_nz call #linepd + + cmp arg7,#2 wz 'if mode 2, set mode 1 + if_z mov arg7,#1 + + add arg4,arg5 'step angle + djnz arg6,#:loop 'loop if more iterations + + jmp #loop +' +' +' vec(x, y, vecscale, vecangle, vecdef_ptr) +' vecarc(x, y, xr, yr, angle, vecscale, vecangle, vecdef_ptr) +' +' vecdef: word $8000/$4000+angle 'vector mode + 13-bit angle (mode: $4000=plot, $8000=line) +' word length 'vector length +' ... 'more vectors +' ... +' word 0 'end of definition +' +vecarc_ call #arcmod + +vec_ tjz arg2,#loop 'if scale 0, exit + +:loop rdword t7,arg4 wz 'get vector mode+angle + add arg4,#2 + + if_z jmp #loop 'if mode+angle 0, exit + + rdword t1,arg4 'get vector length + add arg4,#2 + + abs t2,arg2 wc 'add/sub vector angle to/from angle + mov t6,arg3 + sumc t6,t7 + + call #multiply 'multiply length by scale + add t1,#$80 'round up 1/2 lsb + shr t1,#8 + + mov t4,t1 'get arc dx,dy + mov t5,t1 + call #arcd + + test t7,h8000 wc 'plot pixel or draw line? + if_nc call #plotd + test t7,h8000 wc + if_c call #linepd + + jmp #:loop 'get next vector +' +' +' pix(x, y, pixrot, pixdef_ptr) +' pixarc(x, y, xr, yr, angle, pixrot, pixdef_ptr) +' +' pixdef: word +' byte xwords, ywords, xorigin, yorigin +' word %%xxxxxxxx,%%xxxxxxxx +' word %%xxxxxxxx,%%xxxxxxxx +' word %%xxxxxxxx,%%xxxxxxxx +' ... +' +pixarc_ call #arcmod + +pix_ mov t6,pcolor 'save color + + mov px,dx 'get center into px,py + mov py,dy + + mov sy,pwidth 'get actual pixel width + add sy,#1 + + rdbyte dx,arg3 'get dimensions into dx,dy + add arg3,#1 + rdbyte dy,arg3 + add arg3,#1 + + rdbyte t1,arg3 'get origin and adjust px,py + add arg3,#1 + rdbyte t2,arg3 + add arg3,#1 + neg t2,t2 + sub t2,#1 + add t2,dy + mov t3,sy +:adjust test arg2,#%001 wz + test arg2,#%110 wc + if_z sumnc px,t1 + if_nz sumc py,t1 + test arg2,#%010 wc + if_nz sumnc px,t2 + if_z sumnc py,t2 + djnz t3,#:adjust + +:yline mov sx,#0 'plot entire pix + mov t3,dx +:xword rdword t4,arg3 'read next pix word + add arg3,#2 + shl t4,#16 + mov t5,#8 +:xpixel rol t4,#2 'plot pixel within word + test t4,#1 wc 'set color + muxc pcolor,color1 + test t4,#2 wc + muxc pcolor,color2 wz '(z=1 if color=0) + if_nz call #plotp + test arg2,#%001 wz 'update px,py for next x + test arg2,#%110 wc + if_z sumc px,sy + if_nz sumnc py,sy + add sx,sy + djnz t5,#:xpixel 'another x pixel? + djnz t3,#:xword 'another x word? + if_z sumnc px,sx 'update px,py for next y + if_nz sumc py,sx + test arg2,#%010 wc + if_nz sumc px,sy + if_z sumc py,sy + djnz dy,#:yline 'another y line? + + mov pcolor,t6 'restore color + + jmp #loop +' +' +' text(x, y, @string) justx, justy +' textarc(x, y, xr, yr, angle, @string) justx, justy +' +textarc_ call #arcmod + +text_ add arg3,arg0 'add x into justx + add arg4,arg1 'add y into justy + +:chr rdbyte t1,arg2 wz 'get chr + add arg2,#1 + + if_z jmp #loop 'if 0, done + + sub t1,#$21 'if chr out of range, skip + cmp t1,#$7F-$21+fx wc + if_nc jmp #:skip + + mov arg5,fontptr 'scan font for chr definition +:scan tjz t1,#:def + rdword t2,arg5 + add arg5,#2 + test t2,h8000 wc + if_nc sub t1,#1 + jmp #:scan + +:def rdword t7,arg5 'get font definition word + add arg5,#2 + + call #fontxy 'extract initial x,y + + test t7,#$80 wc 'arc or line? + if_nc jmp #:line + + + mov t2,textsx 'arc, extract x radius + mov t3,#%0001_0001_1 + call #fontb + mov t4,t1 + + mov t2,textsy 'extract y radius + mov t3,#%0010_0011_1 + call #fontb + mov t5,t1 + + mov t2,#1 'extract starting angle + mov t3,#%0010_0011_0 + call #fontb + shl t1,#11 + + mov t6,t1 'extract angle sweep + mov t3,#%0010_0011_0 + call #fontb + neg arg6,t1 + shl arg6,#4 + add arg6,#65 + + call #arcd 'plot initial arc point + call #plotd + +:arc call #arcd 'connect subsequent arc points with lines + call #linepd + add t6,#$80 + djnz arg6,#:arc + + jmp #:more + + +:line call #plotd 'line, plot initial x,y + + call #fontxy 'extract terminal x,y + + call #linepd 'draw line + + +:more test t7,#$02 wc 'more font definition? + if_c jmp #:def + +:skip mov t1,textsp 'advance x to next chr position + mov t2,textsx + call #multiply + add arg3,t1 + + jmp #:chr 'get next chr + + +fontxy mov t2,textsx 'extract x + mov t3,#%0011_0111_0 + call #fontb + mov arg0,t1 + add arg0,arg3 + + mov t2,textsy 'extract y + mov t3,#%0100_1111_0 + call #fontb + mov arg1,t1 + add arg1,arg4 + +setd mov dx,xorigin 'set dx,dy from arg0,arg1 + add dx,arg0 + mov dy,yorigin + sub dy,arg1 +setd_ret +fontxy_ret ret + + +fontb mov t1,t7 'extract bitrange from font word + shr t3,#1 wc + and t1,t3 + if_c add t1,#1 + shr t3,#4 + shr t7,t3 + + shl t1,#32-4 'multiply t1[3..0] by t2 + mov t3,#4 +:loop shl t1,#1 wc + if_c add t1,t2 + djnz t3,#:loop + +fontb_ret ret +' +' +' textmode(x_scale, y_scale, spacing, justification) +' +textmode_ mov textsx,arg0 'set text x scale + mov textsy,arg1 'set text y scale + mov textsp,arg2 'set text spacing + + jmp #loop +' +' +' fill(x, y, da, db, db2, linechange, lines_minus_1) +' +fill_ shl dx,#16 'get left and right fractions + or dx,h8000 + mov t1,dx + + mov t2,xlongs 'get x pixels + shl t2,#4 + + add arg6,#1 'pre-increment line counter + +:yloop add dx,arg2 'adjust left and right fractions + add t1,arg3 + + cmps dx,t1 wc 'get left and right integers + if_c mov base0,dx + if_c mov base1,t1 + if_nc mov base0,t1 + if_nc mov base1,dx + sar base0,#16 + sar base1,#16 + + cmps base0,t2 wc 'left out of range? + if_c cmps hFFFFFFFF,base1 wc 'right out of range? + if_c cmp dy,ylongs wc 'y out of range? + if_nc jmp #:skip 'if any, skip + + mins base0,#0 'limit left and right + maxs base1,t2 wc + if_nc sub base1,#1 + + shl base0,#1 'make left mask + neg mask0,#1 + shl mask0,base0 + shr base0,#5 + + shl base1,#1 'make right mask + xor base1,#$1E + neg mask1,#1 + shr mask1,base1 + shr base1,#5 + + sub base1,base0 wz 'ready long count + add base1,#1 + + if_z and mask0,mask1 'if single long, merge masks + + shl base0,#1 'get long base + add base0,basesptr + rdword base0,base0 + shl dy,#2 + add base0,dy + shr dy,#2 + + mov bits0,mask0 'ready left mask +:xloop mov bits1,pcolor 'make color mask + and bits1,bits0 + rdlong pass,base0 'read-modify-write long + andn pass,bits0 + or pass,bits1 + wrlong pass,base0 + shl ylongs,#2 'advance to next long + add base0,ylongs + shr ylongs,#2 + cmp base1,#2 wz 'one more? + if_nz neg bits0,#1 'if not, ready full mask + if_z mov bits0,mask1 'if one more, ready right mask + djnz base1,#:xloop 'loop if more longs + +:skip sub arg5,#1 wc 'delta change? + if_c mov arg3,arg4 'if so, set new deltas +:same + add dy,#1 'adjust y + djnz arg6,#:yloop 'another y? + + jmp #loop +' +' +' Plot line from px,py to dx,dy +' +linepd cmps dx,px wc, wr 'get x difference + negc sx,#1 'set x direction + + cmps dy,py wc, wr 'get y difference + negc sy,#1 'set y direction + + abs dx,dx 'make differences absolute + abs dy,dy + + cmp dx,dy wc 'determine dominant axis + if_nc tjz dx,#:last 'if both differences 0, plot single pixel + if_nc mov count,dx 'set pixel count + if_c mov count,dy + mov ratio,count 'set initial ratio + shr ratio,#1 + if_c jmp #:yloop 'x or y dominant? + + +:xloop call #plotp 'dominant x line + add px,sx + sub ratio,dy wc + if_c add ratio,dx + if_c add py,sy + djnz count,#:xloop + + jmp #:last 'plot last pixel + + +:yloop call #plotp 'dominant y line + add py,sy + sub ratio,dx wc + if_c add ratio,dy + if_c add px,sx + djnz count,#:yloop + +:last call #plotp 'plot last pixel + +linepd_ret ret +' +' +' Plot pixel at px,py +' +plotd mov px,dx 'set px,py to dx,dy + mov py,dy + +plotp tjnz pwidth,#wplot 'if width > 0, do wide plot + + mov t1,px 'compute pixel mask + shl t1,#1 + mov mask0,#%11 + shl mask0,t1 + shr t1,#5 + + cmp t1,xlongs wc 'if x or y out of bounds, exit + if_c cmp py,ylongs wc + if_nc jmp #plotp_ret + + mov bits0,pcolor 'compute pixel bits + and bits0,mask0 + + shl t1,#1 'get address of pixel long + add t1,basesptr + mov t2,py + rdword t1,t1 + shl t2,#2 + add t1,t2 + + rdlong t2,t1 'write pixel + andn t2,mask0 + or t2,bits0 + wrlong t2,t1 +plotp_ret +plotd_ret ret +' +' +' Plot wide pixel +' +wplot mov t1,py 'if y out of bounds, exit + add t1,#7 + mov t2,ylongs + add t2,#7+8 + cmp t1,t2 wc + if_nc jmp #plotp_ret + + mov t1,px 'determine x long pair + sub t1,#8 + sar t1,#4 + cmp t1,xlongs wc + muxc jumps,#%01 '(use jumps[1..0] to store writes) + add t1,#1 + cmp t1,xlongs wc + muxc jumps,#%10 + + test jumps,#%11 wz 'if x out of bounds, exit + if_z jmp #plotp_ret + + shl t1,#1 'get base pair + add t1,basesptr + rdword base1,t1 + sub t1,#2 + rdword base0,t1 + + mov t1,px 'determine pair shifts + shl t1,#1 + movs :shift1,t1 + xor :shift1,#7<<1 + add t1,#9<<1 + movs :shift0,t1 + test t1,#$F<<1 wz '(account for special case) + if_z andn jumps,#%01 + + mov pass,#0 'ready to plot slices + mov slice,slicesptr + +:loop rdlong mask0,slice 'get next slice + mov mask1,mask0 + +:shift0 shl mask0,#0 'position slice +:shift1 shr mask1,#0 + + mov bits0,pcolor 'colorize slice + and bits0,mask0 + mov bits1,pcolor + and bits1,mask1 + + mov t1,py 'plot lower slice + add t1,pass + cmp t1,ylongs wc + if_c call #wslice + + mov t1,py 'plot upper slice + test pwidth,#1 wc + subx t1,pass + cmp t1,ylongs wc + if_c call #wslice + + add slice,#4 'next slice + add pass,#1 + cmp pass,passes wz + if_nz jmp #:loop + + jmp #plotp_ret +' +' +' Plot wide pixel slice +' +wslice shl t1,#2 'ready long offset + + add base0,t1 'plot left slice + test jumps,#%01 wc + if_c rdlong t2,base0 + if_c andn t2,mask0 + if_c or t2,bits0 + if_c wrlong t2,base0 + + add base1,t1 'plot right slice + test jumps,#%10 wc + if_c rdlong t2,base1 + if_c andn t2,mask1 + if_c or t2,bits1 + if_c wrlong t2,base1 + + sub base0,t1 'restore bases + sub base1,t1 + +wslice_ret ret +' +' +' Get arc point from args and then move args 5..7 to 2..4 +' +arcmod call #arca 'get arc using first 5 args + + mov arg0,dx 'set arg0,arg1 + sub arg0,xorigin + mov arg1,yorigin + sub arg1,dy + + mov arg2,arg5 'move args 5..7 to 2..4 + mov arg3,arg6 + mov arg4,arg7 + +arcmod_ret ret +' +' +' Get arc dx,dy from arg0,arg1 +' +' in: arg0,arg1 = center x,y +' arg2/t4 = x length +' arg3/t5 = y length +' arg4/t6 = 13-bit angle +' +' out: dx,dy = arc point +' +arca mov t4,arg2 'use args + mov t5,arg3 + mov t6,arg4 + +arcd call #setd 'reset dx,dy to arg0,arg1 + + mov t1,t6 'get arc dx + mov t2,t4 + call #polarx + add dx,t1 + + mov t1,t6 'get arc dy + mov t2,t5 + call #polary + sub dy,t1 +arcd_ret +arca_ret ret +' +' +' Polar to cartesian +' +' in: t1 = 13-bit angle +' t2 = 16-bit length +' +' out: t1 = x|y +' +polarx add t1,sine_90 'cosine, add 90° for sine lookup +polary test t1,sine_180 wz 'get sine quadrant 3|4 into nz + test t1,sine_90 wc 'get sine quadrant 2|4 into c + negc t1,t1 'if sine quadrant 2|4, negate table offset + or t1,sine_table 'or in sine table address >> 1 + shl t1,#1 'shift left to get final word address + rdword t1,t1 'read sine/cosine word + call #multiply 'multiply sine/cosine by length to get x|y + add t1,h8000 'add 1/2 lsb to round up x|y fraction + shr t1,#16 'justify x|y integer + negnz t1,t1 'if sine quadrant 3|4, negate x|y +polary_ret +polarx_ret ret + +sine_90 long $0800 '90° bit +sine_180 long $1000 '180° bit +sine_table long $E000 >> 1 'sine table address shifted right +' +' +' Multiply +' +' in: t1 = 16-bit multiplicand (t1[31..16] must be 0) +' t2 = 16-bit multiplier +' +' out: t1 = 32-bit product +' +multiply mov t3,#16 + shl t2,#16 + shr t1,#1 wc + +:loop if_c add t1,t2 wc + rcr t1,#1 wc + djnz t3,#:loop + +multiply_ret ret +' +' +' Defined data +' +zero long 0 'constants +d0 long $200 +h8000 long $8000 +hFFFFFFFF long $FFFFFFFF +color1 long %%1111111111111111 +color2 long %%2222222222222222 + +fontptr long 0 'font pointer (set before cognew command) + +pcolor long %%1111111111111111 'pixel color +pwidth long 0 'pixel width +passes long 1 'pixel passes +textsx long 1 'text scale x +textsy long 1 'text scale y +textsp long 6 'text spacing +' +' +' Undefined data +' +t1 res 1 'temps +t2 res 1 +t3 res 1 +t4 res 1 +t5 res 1 +t6 res 1 +t7 res 1 + +arg0 res 1 'arguments passed from high-level +arg1 res 1 +arg2 res 1 +arg3 res 1 +arg4 res 1 +arg5 res 1 +arg6 res 1 +arg7 res 1 + +basesptr res 1 'pointers +slicesptr res 1 + +xlongs res 1 'bitmap metrics +ylongs res 1 +xorigin res 1 +yorigin res 1 + +dx res 1 'line/plot coordinates +dy res 1 +px res 1 +py res 1 + +sx res 1 'line +sy res 1 +count res 1 +ratio res 1 + +pass res 1 'plot +slice res 1 +base0 res 1 +base1 res 1 +mask0 res 1 +mask1 res 1 +bits0 res 1 +bits1 res 1 + +DAT ' graphics-heap-ende + +grdatend + +{{ ' lizenz + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} + + + diff --git a/source/triborg/triborg-reg.spin b/source/triborg/triborg-reg.spin new file mode 100644 index 0000000..88c78ec --- /dev/null +++ b/source/triborg/triborg-reg.spin @@ -0,0 +1,405 @@ +{{ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Ingo Kripahle │ +│ Copyright (c) 2010 Ingo Kripahle │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : drohne235@googlemail.com +System : TriOS +Name : TriBorg - SID-Player +Chip : Regnatix +Typ : Programm +Version : +Subversion : +Funktion : +Komponenten : - +COG's : - +Logbuch : +Kommandoliste : +Notizen : + +}} + +OBJ + ios: "reg-ios" + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + +SIDMASK = %00000000_00000000_00000000_00010000 + +XMAX = 256 +YMAX = 192 + +x_tiles = 16 +y_tiles = 12 + +bit_base = $2000 +disp_base = $5000 +len_colblk = (x_tiles * y_tiles) * 2 + 256 + +'ademo1 +lines = 5 +thickness = 2 +s_obj = 200 'scale +d_obj = 64 'durchmesser +r_obj = d_obj/2 'radius +rotvar = 14 'rotationsvarianz +arcstep = 16 + +VAR + + 'achtung, folgende reihenfolge darf nicht verändert werden! + word screen[x_tiles * y_tiles] 'tilemap + long colortab[64] 'farbregister + + long heap_len + long heap_use + long dmpreg + + long fcnt + long fpos + long datcnt 'zeiger für dateiliste + byte fl_bye 'flag player beenden +' byte fn[12] 'puffer für dateinamen + + long dmu 'marker des aktuellen userverzeichnisses + +PUB main|i,x,y,n,len + + ios.start + ios.belload(string("triborg.bel")) + ios.g0_dynamic + ios.g0_clear + ios.g0_copy + screenset1 'farben und tiles setzen + heap_len := ios.g0_datlen + ios.g0_datblk(@grdat,0,heap_len) 'heapdaten senden + + ifnot (ios.admgetspec & SIDMASK) + ios.sddmset(ios#DM_USER) 'u-marker setzen + dmu := ios.sddmget(ios#DM_USER) 'usermarker von administra holen + ios.admload(string("triborg.adm")) + ios.sddmput(ios#DM_USER,dmu) 'usermarker wieder in administra setzen + ios.sddmact(ios#DM_USER) 'u-marker aktivieren + + play_count + repeat + ios.sid_sdmpplay(string("triborg.sid")) + \phase1(400) + \phase2(445) + \phase3(250) + \phase4 + play_dir + +PRI esc_key + + if ios.g0_keystat + case ios.g0_keycode + 27: + 'ESC - geordneter rücksturz zur erde... :) + ios.sid_dmpstop 'ok, erstmal die mucke aus + ios.sid_mute(3) + ios.g0_reboot 'grafiksubsystem neu im textmodus starten + ios.admreset 'administra neu starten + waitcnt(cnt+clkfreq*2) 'geben wir den damen noch ein wenig zeit... + reboot + "n": + ios.sid_dmpstop + ios.sid_mute(3) + abort + "p": + ios.sid_dmppause + ios.sid_mute(3) + repeat until ios.g0_keystat + + +PRI screenset1|i,tx,ty + + 'tilescreen setzen + repeat tx from 0 to x_tiles - 1 + repeat ty from 0 to y_tiles - 1 + screen[ty * x_tiles + tx] := disp_base >> 6 + ty + tx * y_tiles + ((ty & $3F) << 10) + + 'farbtabelle füllen + repeat i from 0 to 63 + colortab[i] := $00001010 * (i<<1+4) & $F + $48060D02 + + ios.g0_colortab(@colortab) + ios.g0_screen(@screen) + + +PRI phase1(frcnt) | k + + ios.g0_textmode(5,5,6,0) + ios.g0_colorwidth(2,8) + repeat frcnt + ios.g0_clear + ios.g0_text(15,k,@string4 - @grdat) + ios.g0_copy + k := k + 1 <# 60 + esc_key + +PRI phase2(frcnt) | k + + ios.g0_textmode(5,5,6,0) + ios.g0_colorwidth(2,8) + k := 255 + repeat frcnt + ios.g0_clear + ios.g0_text(15,60,@string4 - @grdat) + ios.g0_text(15,k,@string3 - @grdat) + ios.g0_copy + k := k - 1 #> 60 + esc_key + +PRI phase3(frcnt) | k + + k := 0 + ios.g0_textmode(5,5,6,0) + repeat frcnt + ios.g0_clear + ios.g0_colorwidth(2,8) + ios.g0_text(15,60,@string2 - @grdat) + cores1(400,ymax/2 - 5,cnt>>14,600 + k <# 1600,2) + ios.g0_colorwidth(2,8) + ios.g0_text(15,60,@string1 - @grdat) + ios.g0_copy + k := k + 5 + esc_key + +PRI phase4 | status + + ios.g0_textmode(5,5,6,0) + repeat + dmpreg := ios.sid_dmpreg + status := ios.sid_dmpstatus + ios.g0_clear + ios.g0_colorwidth(2,8) + ios.g0_text(15,60,@string2 - @grdat) + cores2(400,ymax/2 - 5,cnt >> 14,2000,1) + ios.g0_colorwidth(2,8) + ios.g0_text(15,60,@string1 - @grdat) + ios.g0_copy + esc_key + while status + +PRI phase5 | status + + ios.g0_textmode(5,5,6,0) + repeat + dmpreg := ios.sid_dmpreg + status := ios.sid_dmpstatus + ios.g0_clear + ios.g0_colorwidth(2,8) + ios.g0_text(15,60,@string2 - @grdat) + cores2(400,ymax/2 - 5,cnt >> 14,2000,1) + ios.g0_colorwidth(2,8) + ios.g0_text(15,60,@string1 - @grdat) + ios.g0_copy + esc_key + while status + +PRI play(stradr) | status,k + + k := 0 + ios.sid_sdmpplay(stradr) 'sound starten + ios.g0_datblk(@grdat,@fn - @grdat,12) 'dateinamen aktualisieren + repeat + k++ + dmpreg := ios.sid_dmpreg 'sounddaten holen + status := ios.sid_dmpstatus 'playerstatus abfragen + ios.g0_clear + ios.g0_colorwidth(2,8) + ios.g0_textmode(5,5,6,0) + ios.g0_text(15,60,@string2 - @grdat) + cores2(400,ymax/2 - 5,cnt >> 14,2000,1) + ios.g0_colorwidth(2,8) + ios.g0_text(15,60,@string1 - @grdat) + if k < XMAX 'dateiname und zählerstand + ios.g0_textmode(2,1,6,0) + ios.g0_colorwidth(2,0) + ios.g0_text(k,5,@fn - @grdat) + ios.g0_printdec(70,150,fpos,4,@val1,@val1 - @grdat) + ios.g0_printdec(130,150,fcnt,4,@val2,@val2 - @grdat) + + ios.g0_copy + esc_key + while status + ios.sid_dmpstop + +PRI cores1(x,y,angle,radius,col)|x1,y1,x2,y2,x3,y3 + + x1 := x + sin(angle)/(radius) + y1 := y + cos(angle)/(radius) + x2 := x + sin(angle+2730)/(radius) + y2 := y + cos(angle+2730)/(radius) + x3 := x + sin(angle+5460)/(radius) + y3 := y + cos(angle+5460)/(radius) + + ios.g0_colorwidth(0,0) 'startpunkt + ios.g0_plot(x1,y1) + + ios.g0_colorwidth(col, 7) 'kreise + ios.g0_arc(x1, y1, 20, 20, 0, $1fff/(arcstep-1), arcstep, 2) + ios.g0_arc(x2, y2, 20, 20, 0, $1fff/(arcstep-1), arcstep, 2) + ios.g0_arc(x3, y3, 20, 20, 0, $1fff/(arcstep-1), arcstep, 2) + +PRI cores2(x,y,angle,radius,col)|x1,y1,x2,y2,x3,y3,r1,r2,r3,xl,yl + + x1 := x + sin(angle)/(radius - word[dmpreg + 0]>>6) + y1 := y + cos(angle)/(radius - word[dmpreg + 0]>>6) + x2 := x + sin(angle+2730)/(radius - word[dmpreg + 2]>>6) + y2 := y + cos(angle+2730)/(radius - word[dmpreg + 2]>>6) + x3 := x + sin(angle+5460)/(radius - word[dmpreg + 4]>>6) + y3 := y + cos(angle+5460)/(radius - word[dmpreg + 4]>>6) + r1 := byte[dmpreg + 1] >> 3 + r2 := byte[dmpreg + 3] >> 3 + r3 := byte[dmpreg + 5] >> 3 + + ios.g0_colorwidth(2,0) 'startpunkt + ios.g0_plot(x,y) + xl := x + sin(angle+2730)/(500 - word[dmpreg + 0]>>7) + yl := y + cos(angle+2730)/(500 - word[dmpreg + 0]>>7) + ios.g0_line(xl,yl) + + ios.g0_colorwidth(0,0) 'startpunkt + ios.g0_plot(x1,y1) + + ios.g0_colorwidth(col, 7) 'kreise + ios.g0_arc(x1, y1, r1, r1, 0, $1fff/(arcstep-1), arcstep, 2) + ios.g0_arc(x2, y2, r2, r2, 0, $1fff/(arcstep-1), arcstep, 2) + ios.g0_arc(x3, y3, r3, r3, 0, $1fff/(arcstep-1), arcstep, 2) + +PRI cos(angle) : x + x := sin(angle + $800) + +PRI sin(angle) : y + '' Get sine of angle (0-8191) + y := angle << 1 & $FFE ' address + if angle & $800 + y := word[$F000 - y] + else + y := word[$E000 + y] + if angle & $1000 + -y +CON 'sd-player +PRI play_count|stradr,i + + ios.sddir 'kommando: verzeichnis öffnen + datcnt := 0 'zum listenanfang + fcnt := 0 'zähler für dateianzahl + fl_bye := 0 + repeat while (stradr := ios.sdnext) 'dateiliste einlesen + if str_find(stradr,string(".DMP")) + fcnt++ + play_dir_wrlst(stradr) + +PRI play_dir|stradr,len,i 'alle songs auf der sd-card abspielen + + datcnt := 0 'zum listenanfang + repeat i from 0 to fcnt-1 'dateiliste abspielen + fpos := i + 1 + play_dir_rdlst(@fn) + \play(@fn) + + +PRI play_dir_wrlst(stradr)|len,i 'kopiert dateinamen in liste + len := strsize(stradr) + repeat i from 0 to len-1 + ios.ram_wrbyte(ios#usrmod,byte[stradr][i],datcnt++) + ios.ram_wrbyte(ios#usrmod,0,datcnt++) + +PRI play_dir_rdlst(stradr)|i,n 'liest dateinamen aus list + i := 0 + repeat + n := ios.ram_rdbyte(ios#usrmod,datcnt++) + byte[stradr][i++] := n + while n <> 0 + +PRI str_find(string_1, string_2) : buffer | counter 'sys: string suchen + +'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +'' │ Searches a string of characters for the first occurence of the specified string of characters. │ +'' │ │ +'' │ Returns the address of that string of characters if found and zero if not found. │ +'' │ │ +'' │ string1 - A pointer to the string of characters to search. │ +'' │ string2 - A pointer to the string of characters to find in the string of characters to search. │ +'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + + repeat strsize(string_1--) + + if(byte[++string_1] == byte[string_2]) + + repeat counter from 0 to (strsize(string_2) - 1) + + if(byte[string_1][counter] <> byte[string_2][counter]) + buffer~~ + + ifnot(buffer~) + return string_1 + +DAT 'heap-daten + +grdat + +DAT 'stringpuffer + +val1 'stringpuffer für zahlenausgabe +byte "00000000",0 '8 digits +byte 0 'wichtig: auf wortgrenze auffüllen! + +val2 'stringpuffer für zahlenausgabe +byte "00000000",0 '8 digits +byte 0 'wichtig: auf wortgrenze auffüllen! + +strend + + +DAT 'strings + +string1 +byte " rg",0 + +string2 +byte "TriBo",0 + +string3 +byte "Tri",0 + +string4 +byte " Borg",0 + +fn +byte "--------.---",0 + +grdatend + + + +DAT + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}}