├── .gitattributes ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── archive ├── acia_rc2014_prototype.spin ├── text_vga.spin ├── ux_demo.spin └── vga.spin ├── docs ├── FT800 Programmers Guide.pdf ├── MC6850.pdf ├── P8X32A-Web-PropellerManual-v1.2.pdf ├── Propeller Quick Reference v1.7.pdf ├── RC2014_UX_MODULE_DTR.JPG ├── RC2014_UX_MODULE_PREPRODUCTION.JPG ├── RC2014_UX_MODULE_PRODUCTION.JPG ├── RC2014_UX_MODULE_PRODUCTION_BOARD.JPG ├── RC2014_UX_MODULE_PROGAM_STATE.JPG ├── RC2014_UX_MODULE_PROTOTYPE.JPG └── RC2014_UX_MODULE_RUN_STATE.JPG ├── pcb ├── 24LC256.pdf ├── 24LC512.pdf ├── ENG_CD_2311586_D.pdf ├── ENG_CD_5749265_P.pdf ├── MC74HC4078D.pdf ├── P8X32A-Propeller-Datasheet-v1.4.0_0.pdf ├── RC2014_UX_MODULE.brd ├── RC2014_UX_MODULE.sch ├── RC2014_UX_MODULE_BRD.png ├── RC2014_UX_MODULE_ListByParts.csv ├── RC2014_UX_MODULE_ListByValues.csv ├── RC2014_UX_MODULE_NAMES.png ├── RC2014_UX_MODULE_PRODUCTION.zip ├── RC2014_UX_MODULE_SCH.png ├── RC2014_UX_MODULE_VALUES.png ├── TPS7333.pdf ├── ecs-2100x.pdf └── prototype │ ├── RC2014 UX MODULE BRD.png │ ├── RC2014 UX MODULE SCH.png │ ├── RC2014 UX MODULE VALUES.png │ ├── RC2014_UX_MODULE.brd │ ├── RC2014_UX_MODULE.pdf │ └── RC2014_UX_MODULE.sch ├── serial_dtr.py ├── serial_tool.py └── src ├── acia_rc2014.spin ├── hires_text_vga.spin ├── i2c.spin ├── keyboard_ps2.spin ├── lib_vjet ├── VJET_v01_displaylist.spin ├── VJET_vUXM_rendering.spin ├── VJET_vUXM_vga.spin ├── graphtest.spin ├── hexfont.spin └── vjet_test.spin ├── terminal_ftdi.spin ├── ux_module.spin └── wmf_terminal_vga.spin /.gitattributes: -------------------------------------------------------------------------------- 1 | # Line ending normalization 2 | * text=auto 3 | 4 | # Documents 5 | *.doc diff=astextplain 6 | *.DOC diff=astextplain 7 | *.docx diff=astextplain 8 | *.DOCX diff=astextplain 9 | *.dot diff=astextplain 10 | *.DOT diff=astextplain 11 | *.pdf diff=astextplain 12 | *.PDF diff=astextplain 13 | *.rtf diff=astextplain 14 | *.RTF diff=astextplain 15 | *.md text 16 | *.adoc text 17 | *.textile text 18 | *.mustache text 19 | *.csv text 20 | *.tab text 21 | *.tsv text 22 | *.sql text 23 | *.html text 24 | *.css text 25 | 26 | # Graphics 27 | *.png binary 28 | *.jpg binary 29 | *.jpeg binary 30 | *.gif binary 31 | *.tif binary 32 | *.tiff binary 33 | *.ico binary 34 | *.svg binary 35 | *.eps binary 36 | 37 | #sources 38 | *.c text 39 | *.cc text 40 | *.cxx text 41 | *.cpp text 42 | *.c++ text 43 | *.hpp text 44 | *.h text 45 | *.h++ text 46 | *.hh text 47 | *.s text 48 | *.S text 49 | *.asm text 50 | *.spin text 51 | 52 | # Compiled Object files 53 | *.slo binary 54 | *.lo binary 55 | *.o binary 56 | *.obj binary 57 | 58 | # Precompiled Headers 59 | *.gch binary 60 | *.pch binary 61 | 62 | # Compiled Dynamic libraries 63 | *.so binary 64 | *.dylib binary 65 | *.dll binary 66 | 67 | # Compiled Static libraries 68 | *.lai binary 69 | *.la binary 70 | *.a binary 71 | *.lib binary 72 | 73 | # Executables 74 | *.exe binary 75 | *.out binary 76 | *.app binary 77 | *.binary binary 78 | 79 | *.sh text 80 | make text 81 | makefile text 82 | *.mk text 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Executables 3 | *.binary 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at phillip.stevens@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Phillip Stevens 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # User Experience Module 2 | 3 | User Experience Module is designed to use with the RC2014. 4 | 5 | It provides a VGA output, and PS/2 keyboard input. It also provides a FTDI Basic serial connector, which normally operates in parallel to the VGA/keyboard. 6 | 7 | It is designed to operate as an MC68B50 ACIA device (the standard RC2014 Serial Module), so that it can be used without modifying the standard ROMs in circulation. 8 | 9 | I sell on Tindie 10 | 11 | ## Pictures 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
User Experience Module for RC2014 - Production
User Experience Module for RC2014 - Pre-Production
User Experience Module for RC2014 - Production Schematic
User Experience Module for RC2014 - Production Board Layout
50 |
51 | 52 | ## Supported System ROMs 53 | 54 | ### RC2014 Standard 55 | 56 | The UX Module emulates an ACIA interface on base port `0x80`, as per the standard RC2014 usage. Ports `0x80` and `0x81` are required for the implementation. 57 | 58 | This supports the use of [standard RC2014 ROMs](https://github.com/RC2014Z80/RC2014/blob/master/ROMs/Factory/README.md) for MS Basic and CP/M as distributed. These ROMs include: 59 | 60 | - R - Microsoft BASIC, for 32k RAM, 68B50 ACIA, with origin 0x0000 61 | - K - Microsoft BASIC, for 56k RAM, 68B50 ACIA, with origin 0x0000 62 | - 1 - CP/M Monitor, for pageable ROM, 64k RAM, 68B50 ACIA, CF Module at 0x10, with origin at 0x0000 63 | - 88 - Small Computer Monitor for pageable ROM, 64k RAM, SIO/2 or 68B50 ACIA, with Microsoft BASIC and CP/M boot options 64 | - 9 - Small Computer Monitor for any ROM, any RAM, any UART 65 | 66 | ### CP/M-IDE 67 | 68 | The [CP/M-IDE for ACIA](https://github.com/RC2014Z80/RC2014/tree/master/ROMs/CPM-IDE) can be used where an [IDE Interface Module](https://www.tindie.com/products/semachthemonkey/rc2014-ide-hard-drive-module/) is available. 69 | 70 | ### RomWBW 71 | 72 | [RomWBW](https://github.com/wwarthen/RomWBW) is supported, and the UX Module appears as an ACIA port. The UX Module was not compatible with the ACIA device detection mechanism in the 3.0.1 Release, due to the UX Module's tight addressing. However, the device detection mechanism has been improved in the 3.1.1 development branch and it works with the UX Module. 73 | 74 | An optimal configuration of RomWBW is to have the UX Module mapped to `0x40`, and a SIO Module providing `TTY` ports. The minimal boot message for this looks like this... 75 | 76 | ```sh 77 | 78 | RomWBW HBIOS v3.1.1-pre.43, 2021-02-11 79 | 80 | RC2014 Z80 @ 7.372MHz 81 | 0 MEM W/S, 1 I/O W/S, INT MODE 1, Z2 MMU 82 | 512KB ROM, 512KB RAM 83 | 84 | ACIA0: IO=0x40 ACIA MODE=115200,8,N,1 85 | SIO0: IO=0x80 SIO MODE=115200,8,N,1 86 | SIO1: IO=0x82 SIO MODE=115200,8,N,1 87 | MD: UNITS=2 ROMDISK=384KB RAMDISK=256KB 88 | PPIDE: IO=0x20 PPI NOT PRESENT 89 | 90 | Unit Device Type Capacity/Mode 91 | ---------- ---------- ---------------- -------------------- 92 | Char 0 ACIA0: RS-232 115200,8,N,1 93 | Char 1 SIO0: RS-232 115200,8,N,1 94 | Char 2 SIO1: RS-232 115200,8,N,1 95 | Disk 0 MD1: RAM Disk 256KB,LBA 96 | Disk 1 MD0: ROM Disk 384KB,LBA 97 | 98 | 99 | RC2014 Boot Loader 100 | 101 | Boot [H=Help]: 102 | ``` 103 | 104 | To ensure that the UX Module appears as the console port, the console port must be manually set to prefer the UX Module (ACIA) using the `BOOTCON` configuration. The key elements of the configuration file are noted below. 105 | 106 | ```sh 107 | UARTENABLE .SET FALSE ; UART: DISABLE 8250/16550-LIKE SERIAL DRIVER (UART.ASM) 108 | ; 109 | ACIAENABLE .SET TRUE ; ACIA: ENABLE MOTOROLA 6850 ACIA DRIVER (ACIA.ASM) 110 | ACIA0BASE .SET $40 ; ACIA 0: REGISTERS BASE ADDR TO AVOID SIO/2 BASE ADDRESS 111 | ; 112 | SIOENABLE .SET TRUE ; SIO: ENABLE ZILOG SIO SERIAL DRIVER (SIO.ASM) 113 | SIOCNT .SET 1 ; SIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP 114 | ; 115 | TMSENABLE .SET FALSE ; TMS: DISABLE TMS9918 VIDEO/KBD DRIVER (TMS.ASM) 116 | ; 117 | BOOTCON .SET 2 ; SET ACIA AS CONSOLE, ASSUMING 1 SIO/2 MODULE CONFIGURED WITH 2 CHANNELS 118 | ``` 119 | 120 | ## Construction 121 | 122 | Building the UX Module is fairly straightforward. Some notes are included below describing options and potential issues that may arise. 123 | 124 | ### BOM 125 | 126 | The BOM for the UX Module can be found in the Production PCB section of this repository, both listing [by parts](https://github.com/feilipu/ux_module/blob/main/pcb/RC2014_UX_MODULE_ListByParts.csv), and listing [by values](https://github.com/feilipu/ux_module/blob/main/pcb/RC2014_UX_MODULE_ListByValues.csv). 127 | 128 | Also, a complete ordering [Cart is available at Digikey AU](https://www.digikey.com.au/short/47vbdp). 129 | 130 | Note that the 74HC4078 NOR device is not included in the Digikey BOM. This device is obsolete, but can be obtained from UT Source or other ebay sources (or as an option on Tindie). 131 | 132 | Note that sockets are not included in the BOM, but can be used if desired. See the notes on Overclocking below. 133 | 134 | ### SMD 135 | 136 | Soldering the SMD devices is fairly straightforward. The resistors go on the front of the board. They are not polarised, but if you are concerned with neatness they can all be aligned so they face the same way. The capacitors go on the back of the board. The 3x 220pF capacitors are mounted behind the diodes, and this can be noted because of the through-hole on either side of the mounting location. 137 | 138 | There are many techniques for soldering SMD. For a simple tutorial using a standard fine tipped soldering iron and a pair of tweezers, [please refer to this video](https://youtu.be/t7WQLCaeAjM). 139 | 140 | ### EEPROM I2C 141 | 142 | The Parallax Propeller MCU stores its firmware in an external I2C EEPROM. The minimum requirement is for 256kb size (32kB), but the bootloader also supports 512kb size (64kB) devices. Either device is suitable for the UX Module. If you are interested to do additional coding it might be sensible to equip the 512kb device. 143 | 144 | There is no need to put the EEPROM in a socket, as it can be programmed in-situ about a million times (literally) and you're never going to need to exchange it. 145 | 146 | ### Overclocking 147 | 148 | The Parallax Propeller is specified to run at 80MHz. The typical mechanism to achieve this is to provide a 5MHz crystal or oscillator and use the Propeller internal 16x PLL capability to generate the 80MHz system clock. 149 | 150 | Of course this specification can be stretched and the maximum system clock seems to be about 120MHz, noting that this is right on the edge of the capabilities. 151 | 152 | The UX Module is expecting a 7.3728MHz oscillator, the same standard clock as the RC2014 Z80, which produces a 118MHz Propeller system clock. 153 | 154 | It is possible to use a slower oscillator at 5MHz, or 6.25MHz, or other if desired, or in the unlikely event your selected Propeller device doesn't work at 118MHz. In this case the clock rate specification [`_xinfreq`](https://github.com/feilipu/ux_module/blob/main/src/ux_module.spin#L12) will have to be adjusted in the firmware to suit, and the VGA video timing will need to be adjusted to suit. If you are concerned about this it would be sensible to mount the oscillator in a socket to enable it to be simply swapped as needed. 155 | 156 | ## Firmware Development 157 | 158 | The UX Module firmware is developed in Propeller SPIN, and in Propeller Assembly (PASM). The individual functions are mainly built in PASM, with connecting higher level logic running in SPIN. 159 | 160 | ### Development Environment 161 | 162 | There are a number of alternative programming environments for the Parallax Propeller. The PropellerIDE was defined as the default option, and was developed to be cross-platform capable. However, other solutions supporting SPIN, PASM, and C or C++ are also available. 163 | 164 | The UX Module is developed using the PropellerIDE, and therefore support will only provided for issues with that platform. 165 | 166 | The [PropellerIDE](https://developer.parallax.com/propelleride/) is available for Windows, OS X, Linux, and packaged for debian. 167 | 168 | ### Programming Interface 169 | 170 | The UX Module provides a standard FTDI Serial interface for programming. This can optimally be at 3V3, but also works at 5V. References to "Prop Plug" in the PropellerIDE should be taken to mean the FTDI Serial device that you're using. 171 | 172 | When programming the UX Module firmware, it is important that the [upper level code](https://github.com/feilipu/ux_module/blob/main/src/ux_module.spin) be the active window when clicking "compile and upload". The PropellerIDE will compile and upload a sub-module file if it thinks this is what you wanted (because you left it in the foreground). Of course this will lead to things not working as expected. You'll just need to do it again with the upper most code in the foreground. 173 | 174 | ### Source Code Hierarchy 175 | 176 | Propeller SPIN works with modules which help to mask details from driver code from upper level code. 177 | 178 | To implement the functions required for the UX Module several SPIN/PASM modules previously written for Propeller by Parallax have been used. This means that the pretested modules from the Parallax "Object Exchange" are used, and that we can focus on how these modules are integrated. 179 | 180 | The only (at this stage) special PASM functions written for the UX Module are in the implementation of the ACIA MC6850 Serial Interface. These are in the [ACIA module](https://github.com/feilipu/ux_module/blob/main/src/acia_rc2014.spin). 181 | 182 | ``` 183 | ux_module 184 | | 185 | |---> terminal_ftdi 186 | |---> keyboard_ps2 187 | |---> acia_rc2014 188 | |---> i2c 189 | |---> wmf_terminal_vga 190 | | 191 | |---> hires_text_vga 192 | ``` 193 | 194 | ## Usage Notes 195 | 196 | When the UX Module has been programmed successfully, it should boot with `UX Module Initialised` appearing on both VGA interface (screen) and on the FTDI Serial interface. 197 | 198 | To reboot the UX Module the `DTR` on the FTDI interface needs to be toggled. This can be done with the PropellerIDE, or with any serial terminal that can trigger `DTR` toggle. This functionality is used by the Arduino family, so the function is quite common within serial terminals. 199 | 200 | To reboot the UX module if operating stand-alone, the DTR (`GRN`) pin can be touched to the ground (`BLK`) pin on the serial interface, or alternatively touched to the grounded case of the PS/2 keyboard connector. 201 | 202 | Once the UX Module is running the ACIA emulation is enabled, so the RC2014 Z80 can now be rebooted. This can be done by pressing the RESET button on the RC2014 or, if a PS/2 keyboard is attached, by pressing `CTRL+ALT+DEL`. This will now initiate a normal RC2014 boot sequence. 203 | 204 | This video below shows the expected output of a session. 205 | 206 | [![UX Module for RC2014 Operation](https://img.youtube.com/vi/dZT0yxjd9zs/0.jpg)](https://www.youtube.com/watch?v=dZT0yxjd9zs) 207 |
208 | CLICK IMAGE TO VIEW! 209 | 210 | ### Ports 211 | 212 | The UX Module emulates an ACIA interface on base port `0x80`, as per the standard RC2014 usage. Ports `0x80` and `0x81` are required for the implementation. 213 | 214 | The UX Module can be alternately located on ports `0x40`, `0x41` or on `0xC0`, `0xC1`. 215 | 216 | It will (enhancement plan) be possible to implement a graphics interface (VJET library). It is likely that the graphics interface will use the `0xC0` and `0xC1` ports, and may be configured by settings on other ports. 217 | 218 | ### Video VGA 219 | 220 | If you do not have a VGA monitor, it is possible to attach a VGA->HDMI adaptor. The VGA connector on the UX Module supplies 5V to the adaptor so no additional power connection (via USB) is required. The recommended VGA->HDMI adaptor is from [Vention and is available here](https://www.aliexpress.com/item/32844619223.html). 221 | 222 | The VGA timings (front porch and back porch) have been developed using the Vention HDMI adaptor. If an alternative HDMI adaptor or actual VGA monitor is used, the timings may need to be adjusted to ensure that all characters are visible. 223 | 224 | ### Keyboard PS/2 225 | 226 | The keyboard is presumed to be a [USA standard](https://github.com/feilipu/ux_module/blob/main/src/keyboard_ps2.spin) keyboard. Alternate key maps are possible, and can be added to your own build of the firmware. 227 | 228 | ### RC2014 Bus Tx/Rx Line Conflict 229 | 230 | When multiple serial Modules are used on one RC2014 Backplane, there is a potential for conflict on the Tx/Rx lines, Pin 35 and 36. Conflict on the the Bus Tx/Rx lines will prevent the RC2014 from booting correctly. 231 | 232 | The UX Module is connected to the RC2014 Bus serial Tx and Rx lines. When using the UX Module with other serial Modules (such as the SIO/2 Module), it is necessary to disconnect one or other of the serial Modules. In practice the easiest way to do this is to straighten either the UX Module or SIO/2 Module Tx and Rx pins sufficiently so that they do not insert into the Bus connector. 233 | 234 | ## Errata Propeller /RESET Pin 235 | 236 | The Propeller MCU `/RESET` pin is driven by the serial interface `DTR` pin, which is normally held high when the port is ready. However sometimes both Linux (MacOS) and Windows toggle `DTR` when opening a new serial interface. This impacts our ability to use the serial interface to upload code to the RC2014. 237 | 238 | There are several options proposed on the internet to avoid this issue (mainly driven by Arduino users wanting to have "long running" code). The solutions are written into the [`serial_tool.py`](https://github.com/feilipu/ux_module/blob/main/serial_tool.py) which is included to simplify uploading BASIC programs to the RC2014. 239 | 240 | For some machines, none of the software options work so the final solution is to bend the `DTR` pin out from the FTDI connector. Then an optional connection can be provided to enable Propeller reprogramming. Photos demonstrating one method to do this are provided in the [`docs`](https://github.com/feilipu/ux_module/tree/main/docs) directory. 241 | 242 | 243 | ## Code of conduct 244 | 245 | See the [Code of Conduct](https://github.com/feilipu/ux_module/blob/main/CODE_OF_CONDUCT.md). 246 | 247 | -------------------------------------------------------------------------------- /archive/acia_rc2014_prototype.spin: -------------------------------------------------------------------------------- 1 | '' 2 | '' UX Module RC2014 Bus Interface 3 | '' 4 | '' ACIA emulation 5 | '' 6 | '' Copyright (c) 2020 Phillip Stevens 7 | '' 8 | '' I/O Address line mapping (Production): 9 | '' 10 | '' P7 P6 P5 P4 P3 P2 P1 P0 11 | '' x x 1 1 x 1 x x 12 | '' | | | | | | | | 13 | '' | | | | | | | | 14 | '' /RD ---+ | | | | | | | 15 | '' /WR -------+ | | | | | | 16 | '' /RESET --------+ | | | | | 17 | '' /M1 ---------------+ | | | | 18 | '' A0 --------------------+ | | | 19 | '' !(/IORQ|A5|A4|A3|A2|A1) ---+ | | 20 | '' A6 ----------------------------+ | 21 | '' A7 --------------------------------+ 22 | '' 23 | '' 24 | '' I/O Address line mapping (OBSOLETE): 25 | '' Only 1 PROTOTYPE device built. 26 | '' 27 | '' P7 P6 P5 P4 P3 P2 P1 P0 28 | '' 0 x x 1 x 0 x x 29 | '' | | | | | | | | 30 | '' | | | | | | | | 31 | '' /IORQ -+ | | | | | | | 32 | '' /RD -------+ | | | | | | 33 | '' /WR -----------+ | | | | | 34 | '' /M1 ---------------+ | | | | 35 | '' A0 --------------------+ | | | 36 | '' A5|A4|A3|A2|A1 ------------+ | | 37 | '' A6 ----------------------------+ | 38 | '' A7 --------------------------------+ 39 | '' 40 | '' 41 | '' I/O Data line mapping: 42 | '' 43 | '' P15 P14 P13 P12 P11 P10 P9 P8 44 | '' x x x x x x x x 45 | '' | | | | | | | | 46 | '' | | | | | | | | 47 | '' D7 ----+ | | | | | | | 48 | '' D6 --------+ | | | | | | 49 | '' D5 ------------+ | | | | | 50 | '' D4 ----------------+ | | | | 51 | '' D3 --------------------+ | | | 52 | '' D2 ------------------------+ | | 53 | '' D1 ----------------------------+ | 54 | '' D0 --------------------------------+ 55 | '' 56 | '' 57 | '' I/O Signal line mapping: 58 | '' 59 | '' P25 P24 60 | '' x x 61 | '' | | 62 | '' | | 63 | '' INT ---+ | 64 | '' WAIT ------+ 65 | '' 66 | 67 | CON 68 | 69 | DATA_BASE = 8 'DATA bus is Pin P8 to Pin P15 70 | DATA_PINS = %1111_1111 '8 bit data bus 71 | 72 | INT_PIN_NUM = 25 73 | INT_PIN = |< INT_PIN_NUM 74 | WAIT_PIN = |< 24 75 | 76 | IORQ_PIN = |< 7 77 | RD_PIN = |< 6 78 | WR_PIN = |< 5 79 | M1_PIN = |< 4 80 | 81 | A0_PIN = |< 3 82 | A5_A1_PINS = |< 2 83 | A6_PIN = |< 1 84 | A7_PIN = |< 0 85 | 86 | BUFFER_LENGTH = 512 'Recommended as 64 or higher, but can be 2, 4, 8, 16, 32, 64, 128, 256 or 512. 87 | BUFFER_MASK = BUFFER_LENGTH - 1 88 | 89 | MAX_STRING = 255 90 | 91 | CON 92 | 93 | PORT_00 = 0 94 | PORT_01 = A0_PIN 95 | 96 | PORT_40 = A6_PIN 97 | PORT_41 = A6_PIN | A0_PIN 98 | 99 | PORT_80 = A7_PIN 100 | PORT_81 = A7_PIN | A0_PIN 101 | 102 | PORT_C0 = A7_PIN | A6_PIN 103 | PORT_C1 = A7_PIN | A6_PIN | A0_PIN 104 | 105 | PORT_MASK = A7_PIN | A6_PIN | A5_A1_PINS 106 | 107 | ' ACIA Control Register 108 | 109 | CR_RIE = |< 7 ' Receiving Interrupt Enabled (Z80 view) 110 | 111 | CR_TXI_MASK = |< 6 | |< 5 ' Mask just the Tx Interrupt bits 112 | 113 | CR_TDI_BRK = |< 6 | |< 5 ' _RTS low, Transmitting Interrupt Disabled, BRK on Tx 114 | CR_TDI_RTS1 = |< 6 ' _RTS high, Transmitting Interrupt Disabled 115 | CR_TEI_RTS0 = |< 5 ' _RTS low, Transmitting Interrupt Enabled 116 | CR_TDI_RTS0 = 0 ' _RTS low, Transmitting Interrupt Disabled 117 | 118 | CR_8O1 = |< 4 | |< 3 | |< 2 ' 8 Bits Odd Parity 1 Stop Bit 119 | CR_8E1 = |< 4 | |< 3 ' 8 Bits Even Parity 1 Stop Bit 120 | CR_8N1 = |< 4 | |< 2 ' 8 Bits No Parity 1 Stop Bit 121 | CR_8N2 = |< 4 ' 8 Bits No Parity 2 Stop Bits 122 | CR_7O1 = |< 3 | |< 2 ' 7 Bits Odd Parity 1 Stop Bit 123 | CR_7E1 = |< 3 ' 7 Bits Even Parity 1 Stop Bit 124 | CR_7O2 = |< 2 ' 7 Bits Odd Parity 2 Stop Bits 125 | CR_7E2 = 0 ' 7 Bits Even Parity 2 Stop Bits 126 | 127 | CR_RESET = |< 1 | |< 0 ' Master Reset (issue before any other Control word) 128 | CR_DIV_64 = |< 1 ' Divide the Clock by 64 (default value) 129 | CR_DIV_16 = |< 0 ' Divide the Clock by 16 130 | CR_DIV_01 = 0 ' Divide the Clock by 1 131 | 132 | ' ACIA Status Register 133 | 134 | SR_IRQ = |< 7 135 | SR_PE = |< 6 136 | SR_OVRN = |< 5 137 | SR_FE = |< 4 138 | SR_CTS = |< 3 139 | SR_DCD = |< 2 140 | SR_TDRE = |< 1 141 | SR_RDRF = |< 0 142 | 143 | 144 | VAR 145 | 146 | long cog 'cog flag/id 147 | 148 | '7 contiguous longs 149 | long rx_head '#0 index into rx_buffer 150 | long rx_tail '#4 151 | long tx_head '#8 152 | long tx_tail '#12 153 | long acia_config '#16 ACIA configuration byte stored shifted by DATA_BASE 154 | long acia_status '#20 ACIA status byte stored shifted by DATA_BASE 155 | long buffer_ptr '#24 156 | byte rx_buffer[BUFFER_LENGTH] '#28 transmit and receive buffers for ACIA emulation 157 | byte tx_buffer[BUFFER_LENGTH] '#28 + BUFFER_LENGTH 158 | 159 | 160 | PUB start(base) : okay 161 | {{ 162 | Starts RC2014 acia bus driver in a new cog 163 | okay - returns false if no cog is available. 164 | }} 165 | 166 | stop 167 | longfill(@rx_head, 0, 4) ' These are indexes to bytes in the buffer, not pointers 168 | port_base_addr := base ' Use DAT variables to make the assignment stick for later cog usage 169 | acia_config := constant (( CR_TDI_RTS0 | CR_8N1 | CR_DIV_64 ) << DATA_BASE ) 170 | acia_status := constant ( SR_TDRE << DATA_BASE ) ' Always ready to receive bytes from the Z80 171 | buffer_ptr := @rx_buffer ' Record the origin address of the Rx and Tx buffers 172 | okay := cog := cognew(@entry,@rx_head) + 1 173 | 174 | 175 | PUB stop 176 | 177 | '' Stops acia driver - frees a cog 178 | 179 | if cog 180 | cogstop(cog~ - 1) 181 | longfill(@rx_head, 0, 7) 182 | 183 | 184 | PUB txString( pStringPtr ) 185 | 186 | '' Print a zero-terminated string to terminal. 187 | '' pStrPtr - Pointer to null terminated string to print. 188 | 189 | repeat strsize( pStringPtr) 190 | tx(byte[pStringPtr++]) 191 | 192 | 193 | PUB tx(txbyte) 194 | 195 | '' Sends byte (may wait for room in buffer) 196 | 197 | repeat until (tx_tail - tx_head) & BUFFER_MASK <> 1 ' Wait until buffer is not full 198 | 199 | tx_buffer[tx_head] := txbyte 200 | tx_head := ++tx_head & BUFFER_MASK 201 | 202 | acia_status |= constant ( SR_RDRF << DATA_BASE ) ' Byte ready to transmit to Z80 203 | 204 | if acia_config & constant ( CR_RIE << DATA_BASE ) ' If the Rx interrupt (Z80 perspective) is not set, then set it 205 | acia_status |= constant ( SR_IRQ << DATA_BASE ) ' Set the interrupt status byte (cleared in driver cog) 206 | dira[ INT_PIN_NUM ]~~ ' Set /INT pin to output to wake up the Z80 (minimum 136ns pulse = 1 RC2014 standard clock) 207 | dira[ INT_PIN_NUM ]~ ' Set /INT pin to input (measured pulse is 5,600ns) 208 | 209 | 210 | PUB rx : rxbyte 211 | 212 | '' Receive single-byte character. Waits until character received. 213 | '' Returns: $00..$FF 214 | 215 | repeat while (!rxCheck) 216 | rxbyte := rx_buffer[rx_tail] 217 | rx_tail := ++rx_tail & BUFFER_MASK 218 | 219 | 220 | PUB rxCount : count 221 | 222 | '' Get count of characters in receive buffer 223 | '' Returns: number of characters waiting in receive buffer 224 | 225 | count := rx_head - rx_tail 226 | count -= BUFFER_LENGTH * (count < 0) 227 | 228 | 229 | PUB rxFlush 230 | 231 | '' Flush receive buffer 232 | 233 | rx_tail := rx_head := 0 234 | 235 | 236 | PUB rxCheck : truefalse 237 | 238 | '' Check if character received; return immediately. 239 | '' Returns: t|f 240 | 241 | truefalse := rx_tail <> rx_head 242 | 243 | 244 | DAT 245 | 246 | '**************************************** 247 | '* Assembly language ACIA Z80 Emulation * 248 | '**************************************** 249 | 250 | org 251 | ' 252 | ' 253 | ' Entry 254 | ' 255 | entry 256 | mov t1,par ' get structure address 257 | 258 | add t1,#16 ' get acia_config address 259 | mov acia_config_addr,t1 260 | 261 | add t1,#4 ' get acia_status address 262 | mov acia_status_addr,t1 263 | 264 | add t1,#4 ' resolve buffer addresses using buffer_ptr 265 | rdlong rxbuff,t1 ' rx_buffer base address is stored there 266 | mov txbuff,rxbuff ' tx_buffer base address is rx_buffer + BUFFER_LENGTH 267 | add txbuff,#BUFFER_MASK ' BUFFER_LENGTH := BUFFER_MASK + 1 268 | add txbuff,#1 269 | 270 | mov dira,bus_wait ' set /WAIT pin to output 271 | mov outa,bus_wait ' clear /WAIT high by default 272 | ' it is behind a diode, and the bus is open collector 273 | 274 | or port_base_addr,bus_m1 ' add in the /M1 pin to tighten addressing 275 | or port_base_addr,bus_wait ' add the /WAIT pin to the address for waitpeq wr effect 276 | 277 | wait 278 | mov outa,port_base_addr ' configure the base address to compare with ina 279 | ' including /WAIT pin 280 | 281 | waitpne outa,port_active_mask 282 | waitpeq outa,port_active_mask wr' wait until we see our addresses, together with /IORQ low 283 | ' use wr effect to set /WAIT low on match (/INT gets hit as a side effect) 284 | 285 | andn outa,bus_int ' reset /INT pin (modified as a side effect of the waitpeq outa wr effect) 286 | 287 | testn bus_a0,ina wz ' isolate the base address 288 | if_z jmp #handler_data ' handle data, otherwise fall through for handling command/status at base address 289 | 290 | testn bus_rd,ina wz ' capture port data again, test for /RD pin low 291 | if_nz jmp #transmit_status 292 | 293 | testn bus_wr,ina wz ' capture port data again, test for /WR pin low 294 | if_nz jmp #receive_command 295 | 296 | jmp #wait ' then go back and wait for next address chance 297 | 298 | handler_data 299 | rdlong t1,acia_status_addr 300 | andn t1,acia_status_irq ' clear the interrupt status bit, because we've handled data 301 | and t1,data_active_mask ' mask to the status byte 302 | wrlong t1,acia_status_addr 303 | 304 | testn bus_rd,ina wz ' capture port data again, test for /RD pin low 305 | if_nz jmp #transmit_data 306 | 307 | testn bus_wr,ina wz ' capture port data again, test for /WR pin low 308 | if_nz jmp #receive_data 309 | 310 | jmp #wait ' then go back and wait for next address chance 311 | 312 | receive_command 313 | or outa,bus_wait ' set /WAIT line high to continue 314 | mov bus,ina ' capture the command byte (stored shifted by DATA_BASE) 315 | waitpeq bus_wr,bus_wr ' wait for /WR high 316 | and bus,data_active_mask ' mask received command byte 317 | wrlong bus,acia_config_addr 318 | xor bus,acia_config_reset wz' master reset if we've received the RESET command 319 | if_nz jmp #wait 320 | 321 | wrlong acia_config_initial,acia_config_addr ' reset config 322 | wrlong acia_status_initial,acia_status_addr ' reset status 323 | jmp #wait 324 | 325 | transmit_status 326 | rdlong bus,acia_status_addr ' get the status byte 327 | and bus,data_active_mask ' mask transmitted status byte 328 | or outa,bus ' transmit the status byte (stored shifted by DATA_BASE) 329 | or dira,data_active_mask ' set data lines to active (output) 330 | or outa,bus_wait ' set /WAIT line high to continue 331 | waitpeq bus_rd,bus_rd ' wait for /RD to raise 332 | andn dira,data_active_mask ' set data lines to inactive (input) 333 | andn outa,data_active_mask ' set data lines to zero 334 | jmp #wait 335 | 336 | receive_data 337 | or outa,bus_wait ' set /WAIT line high to continue 338 | mov bus,ina ' capture the data byte 339 | waitpeq bus_wr,bus_wr ' wait for /WR high 340 | shr bus,#DATA_BASE ' shift data so that the LSB corresponds with D0 341 | rdlong t2,par ' assign value of rx_head to t2 342 | add t2,rxbuff ' create the pointer to the location to write 343 | wrbyte bus,t2 ' write the byte (in bus) to address in t2 344 | sub t2,rxbuff ' recover value 345 | add t2,#1 ' increment the head pointer 346 | and t2,#BUFFER_MASK ' and check for range (if > #BUFFER_MASK then rollover) 347 | wrlong t2,par ' write the temporary value back to par 348 | 349 | rdlong t1,acia_config_addr 350 | and t1,acia_config_int_tx_mask ' mask out the tx interrupt bits. 351 | xor t1,acia_config_int_tx wz' test whether the interrupt pin should be set 352 | if_nz jmp #wait ' receive byte done 353 | 354 | jmp #set_interrupt ' set the interrupt if needed 355 | 356 | transmit_data ' check for head <> tail 357 | mov t1,par ' get address of rx_head assign it to t1 358 | add t1,#8 ' increment t1 by 8 bytes. Result is address of tx_head 359 | rdlong t2,t1 ' copy value of tx_head into t2 360 | add t1,#4 ' increment t1 by 4 bytes. Result is address of tx_tail 361 | rdlong t3,t1 ' copy value of tx_tail into t3 362 | cmp t2,t3 wz ' compare tx_tail and tx_head 363 | 364 | add t3,txbuff ' add address of txbuff to value of tx_tail 365 | rdbyte bus,t3 ' read byte from the tail of the buffer into bus 366 | sub t3,txbuff ' subtract address of bus (Result is tx_tail) 367 | if_ne add t3,#1 ' increment t3 by 1 byte (same as tx_tail + 1) 368 | if_ne and t3,#BUFFER_MASK ' and check for range (if > #BUFFER_MASK then rollover) 369 | if_ne wrlong t3,t1 ' write long value of t3 into address tx_tail 370 | 371 | shl bus,#DATA_BASE ' shift data so that the LSB corresponds with DATA_BASE 372 | or outa,bus ' write byte to Parallel FIFO 373 | or dira,data_active_mask ' set data lines to active (output) 374 | or outa,bus_wait ' set /WAIT line high to continue 375 | waitpeq bus_rd,bus_rd ' wait for /RD to raise 376 | andn dira,data_active_mask ' set data lines to inactive (input) 377 | andn outa,data_active_mask ' set data lines to zero 378 | 379 | if_e rdlong t1,acia_status_addr 380 | if_e andn t1,acia_status_rdrf ' if no further bytes, clear RDRF 381 | if_e and t1,data_active_mask ' mask transmitted byte 382 | if_e wrlong t1,acia_status_addr 383 | if_e jmp #wait ' transmit byte done 384 | 385 | rdlong t1,acia_config_addr 386 | test t1,acia_config_int_rx wz' test whether the rx interrupt pin should be set 387 | if_z jmp #wait 388 | 389 | mov t1,par ' get address of rx_head assign it to t1 390 | add t1,#8 ' increment t1 by 8 bytes. Result is address of tx_head 391 | rdlong t2,t1 ' copy value of tx_head into t2 392 | add t1,#4 ' increment t1 by 4 bytes. Result is address of tx_tail 393 | rdlong t3,t1 ' copy value of tx_tail into t3 394 | cmp t2,t3 wz ' compare tx_tail and tx_head, continue if no bytes available 395 | if_z jmp #wait ' transmit byte done 396 | 397 | set_interrupt 398 | rdlong t1,acia_status_addr 399 | or dira,bus_int ' set /INT pin to output for minimum 136ns (1 RC2014 clock) 400 | or t1,acia_status_irq ' set the interrupt status bit 401 | wrlong t1,acia_status_addr 402 | andn dira,bus_int ' clear /INT pin 403 | jmp #wait ' set interrupt done 404 | 405 | ' 406 | ' Constants 407 | ' 408 | bus_wait long WAIT_PIN 409 | bus_int long INT_PIN 410 | 411 | bus_rd long RD_PIN 412 | bus_wr long WR_PIN 413 | bus_m1 long M1_PIN 414 | 415 | bus_a0 long A0_PIN 416 | 417 | port_active_mask long WAIT_PIN | IORQ_PIN | M1_PIN | PORT_MASK 418 | data_active_mask long DATA_PINS << DATA_BASE 419 | 420 | acia_config_initial long ( CR_TDI_RTS0 | CR_8N1 | CR_DIV_64 ) << DATA_BASE 421 | acia_status_initial long ( SR_TDRE ) << DATA_BASE 422 | 423 | acia_config_reset long ( CR_RESET ) << DATA_BASE 424 | acia_config_int_rx long ( CR_RIE ) << DATA_BASE 425 | acia_config_int_tx long ( CR_TEI_RTS0 ) << DATA_BASE 426 | acia_config_int_tx_mask long ( CR_TXI_MASK ) << DATA_BASE 427 | 428 | acia_status_irq long ( SR_IRQ ) << DATA_BASE 429 | acia_status_rdrf long ( SR_RDRF ) << DATA_BASE 430 | 431 | ' 432 | ' Uninitialized data 433 | ' 434 | port_base_addr res 1 435 | 436 | acia_config_addr res 1 437 | acia_status_addr res 1 438 | 439 | rxbuff res 1 440 | txbuff res 1 441 | 442 | t1 res 1 443 | t2 res 1 444 | t3 res 1 445 | 446 | bus res 1 447 | 448 | fit 449 | 450 | 451 | DAT 452 | 453 | {{ 454 | +------------------------------------------------------------------------------------------------------------------------------+ 455 | | TERMS OF USE: MIT License | 456 | +------------------------------------------------------------------------------------------------------------------------------+ 457 | |Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation | 458 | |files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, | 459 | |modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software| 460 | |is furnished to do so, subject to the following conditions: | 461 | | | 462 | |The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.| 463 | | | 464 | |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 465 | |WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | 466 | |COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 467 | |ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 468 | +------------------------------------------------------------------------------------------------------------------------------+ 469 | }} -------------------------------------------------------------------------------- /archive/text_vga.spin: -------------------------------------------------------------------------------- 1 | ''*************************************** 2 | ''* VGA Text 40x15 v1.0 [Modified] * 3 | ''* Author: Chip Gracey * 4 | ''* Copyright (c) 2006 Parallax, Inc. * 5 | ''* See end of file for terms of use. * 6 | ''*************************************** 7 | 8 | ''Modified 081715. 9 | ''Allows use of VGA monitor on systems 10 | ''running at 118MHz (7.3728MHz crystal). 11 | '' 12 | ''Monitor states: 13 | '' 14 | '' 640x480 15 | '' 25.175kHz 60Hz 16 | '' 17 | ''Ref DATA method below. 18 | ''GGysbers 19 | 20 | CON 21 | 22 | cols = 40 23 | rows = 15 24 | 25 | screensize = cols * rows 26 | lastrow = screensize - cols 27 | 28 | vga_count = 21 29 | lastrow = screensize - cols 30 | 31 | vga_count = 21 32 | 33 | 34 | VAR 35 | 36 | long col, row, color, flag 37 | 38 | word screen[screensize] 39 | long colors[8 * 2] 40 | 41 | long vga_status '0/1/2 = off/visible/invisible read-only (21 longs) 42 | long vga_enable '0/non-0 = off/on write-only 43 | long vga_pins '%pppttt = pins write-only 44 | long vga_mode '%tihv = tile,interlace,hpol,vpol write-only 45 | long vga_screen 'pointer to screen (words) write-only 46 | long vga_colors 'pointer to colors (longs) write-only 47 | long vga_ht 'horizontal tiles write-only 48 | long vga_vt 'vertical tiles write-only 49 | long vga_hx 'horizontal tile expansion write-only 50 | long vga_vx 'vertical tile expansion write-only 51 | long vga_ho 'horizontal offset write-only 52 | long vga_vo 'vertical offset write-only 53 | long vga_hd 'horizontal display ticks write-only 54 | long vga_hf 'horizontal front porch ticks write-only 55 | long vga_hs 'horizontal sync ticks write-only 56 | long vga_hb 'horizontal back porch ticks write-only 57 | long vga_vd 'vertical display lines write-only 58 | long vga_vf 'vertical front porch lines write-only 59 | long vga_vs 'vertical sync lines write-only 60 | long vga_vb 'vertical back porch lines write-only 61 | long vga_rate 'tick rate (Hz) write-only 62 | 63 | 64 | OBJ 65 | 66 | vga : "vga" 67 | 68 | 69 | PUB start(basepin) : okay 70 | 71 | '' Start terminal - starts a cog 72 | '' returns false if no cog available 73 | '' 74 | '' requires at least 80MHz system clock 75 | 76 | setcolors(@palette) 77 | out(0) 78 | 79 | longmove(@vga_status, @vga_params, vga_count) 80 | vga_pins := basepin | %000_111 81 | vga_screen := @screen 82 | vga_colors := @colors 83 | 84 | okay := vga.start(@vga_status) 85 | 86 | 87 | PUB stop 88 | 89 | '' Stop terminal - frees a cog 90 | 91 | vga.stop 92 | 93 | 94 | PUB str(stringptr) 95 | 96 | '' Print a zero-terminated string 97 | 98 | repeat strsize(stringptr) 99 | out(byte[stringptr++]) 100 | 101 | 102 | PUB dec(value) | i 103 | 104 | '' Print a decimal number 105 | 106 | if value < 0 107 | -value 108 | out("-") 109 | 110 | i := 1_000_000_000 111 | 112 | repeat 10 113 | if value => i 114 | out(value / i + "0") 115 | value //= i 116 | result~~ 117 | elseif result or i == 1 118 | out("0") 119 | i /= 10 120 | 121 | 122 | PUB hex(value, digits) 123 | 124 | '' Print a hexadecimal number 125 | 126 | value <<= (8 - digits) << 2 127 | repeat digits 128 | out(lookupz((value <-= 4) & $F : "0".."9", "A".."F")) 129 | 130 | 131 | PUB bin(value, digits) 132 | 133 | '' Print a binary number 134 | 135 | value <<= 32 - digits 136 | repeat digits 137 | out((value <-= 1) & 1 + "0") 138 | 139 | 140 | PUB out(c) | i, k 141 | 142 | '' Output a character 143 | '' 144 | '' $00 = clear screen 145 | '' $01 = home 146 | '' $08 = backspace 147 | '' $09 = tab (8 spaces per) 148 | '' $0A = set X position (X follows) 149 | '' $0B = set Y position (Y follows) 150 | '' $0C = set color (color follows) 151 | '' $0D = return 152 | '' others = printable characters 153 | 154 | case flag 155 | $00: case c 156 | $00: wordfill(@screen, $220, screensize) 157 | col := row := 0 158 | $01: col := row := 0 159 | $08: if col 160 | col-- 161 | $09: repeat 162 | print(" ") 163 | while col & 7 164 | $0A..$0C: flag := c 165 | return 166 | $0D: newline 167 | other: print(c) 168 | $0A: col := c // cols 169 | $0B: row := c // rows 170 | $0C: color := c & 7 171 | flag := 0 172 | 173 | 174 | PUB setcolors(colorptr) | i, fore, back 175 | 176 | '' Override default color palette 177 | '' colorptr must point to a list of up to 8 colors 178 | '' arranged as follows (where r, g, b are 0..3): 179 | '' 180 | '' fore back 181 | '' ------------ 182 | '' palette byte %%rgb, %%rgb 'color 0 183 | '' byte %%rgb, %%rgb 'color 1 184 | '' byte %%rgb, %%rgb 'color 2 185 | '' ... 186 | 187 | repeat i from 0 to 7 188 | fore := byte[colorptr][i << 1] << 2 189 | back := byte[colorptr][i << 1 + 1] << 2 190 | colors[i << 1] := fore << 24 + back << 16 + fore << 8 + back 191 | colors[i << 1 + 1] := fore << 24 + fore << 16 + back << 8 + back 192 | 193 | 194 | PRI print(c) 195 | 196 | screen[row * cols + col] := (color << 1 + c & 1) << 10 + $200 + c & $FE 197 | if ++col == cols 198 | newline 199 | 200 | 201 | PRI newline | i 202 | 203 | col := 0 204 | if ++row == rows 205 | row-- 206 | wordmove(@screen, @screen[cols], lastrow) 'scroll lines 207 | wordfill(@screen[lastrow], $220, cols) 'clear new line 208 | 209 | 210 | DAT 211 | 212 | '640x480 @ 60Hz 213 | vga_params long 0 'status 214 | long 1 'enable 215 | long 0 'pins 216 | long %1000 'mode 217 | long 0 'videobase 218 | long 0 'colorbase 219 | long cols 'hc 220 | long rows 'vc 221 | long 1 'hx 222 | long 1 'vx 223 | long 0 'ho 224 | long 0 'vo 225 | long 640 'hd 226 | long 16 'hf 227 | long 96 'hs 228 | long 48 'hb 229 | long 480 'vd 230 | long 10 'vf 231 | long 2 'vs 232 | long 33 'vb 233 | long 25_175_000 'rate 234 | 235 | ' fore back 236 | ' RGB RGB 237 | palette byte %%333, %%001 '0 white / dark blue 238 | byte %%330, %%110 '1 yellow / brown 239 | 'byte %%202, %%000 '2 magenta / black 240 | byte %%333, %%001 '2 white / dark blue 241 | byte %%111, %%333 '3 grey / white 242 | byte %%033, %%011 '4 cyan / dark cyan 243 | byte %%020, %%232 '5 green / gray-green 244 | byte %%100, %%311 '6 red / pink 245 | byte %%033, %%003 '7 cyan / blue 246 | 247 | DAT 248 | 249 | {{ 250 | +------------------------------------------------------------------------------------------------------------------------------+ 251 | | TERMS OF USE: MIT License | 252 | +------------------------------------------------------------------------------------------------------------------------------+ 253 | |Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation | 254 | |files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, | 255 | |modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software| 256 | |is furnished to do so, subject to the following conditions: | 257 | | | 258 | |The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.| 259 | | | 260 | |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 261 | |WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | 262 | |COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 263 | |ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 264 | +------------------------------------------------------------------------------------------------------------------------------+ 265 | }} -------------------------------------------------------------------------------- /archive/ux_demo.spin: -------------------------------------------------------------------------------- 1 | ''*************************************** 2 | ''* User Experience Module * 3 | ''* Designed for RC2014 * 4 | ''* Author: Phillip Stevens * 5 | ''* Copyright (c) 2020 * 6 | ''* See end of file for licence * 7 | ''*************************************** 8 | 9 | CON 10 | 11 | _clkmode = XTAL1 + PLL16X 12 | _xinfreq = 7_372_800 13 | 14 | CON 15 | 16 | ' import some constants from the ACIA Emulation 17 | PORT_40 = acia#PORT_40 18 | PORT_80 = acia#PORT_80 ' Default ACIA base port 19 | PORT_C0 = acia#PORT_C0 20 | 21 | CON 22 | 23 | ' set these constants based on the Propeller VGA hardware 24 | VGA_BASE_PIN = 16 ' VGA pins 16-23 25 | 26 | ' set these constants based on the Propeller PS/2 hardware 27 | KBD_DATA_PIN = 27 ' KEYBOARD data pin 28 | KBD_CLK_PIN = 26 ' KEYBOARD clock pin 29 | 30 | 31 | VAR 32 | 33 | ' ----------------------------------------------------------------------------- 34 | ' DECLARED VARIABLES, ARRAYS, ETC. 35 | ' ----------------------------------------------------------------------------- 36 | 37 | byte gVgaRows, gVgaCols ' convenient globals to store number of columns and rows 38 | 39 | byte gStrBuff1[64] ' some string buffers 40 | byte gStrBuff2[64] 41 | 42 | ' these data structures contains two cursors in the format [x,y,mode] 43 | ' these are passed to the VGA driver, so it can render them over the text in the display 44 | ' like "hardware" cursors, that don't disturb the graphics under them. We can use them 45 | ' to show where the text cursor and mouse cursor is 46 | ' The data structure is 6 contiguous bytes which we pass to the VGA driver ultimately 47 | 48 | byte gTextCursX, gTextCursY, gTextCursMode ' text cursor 0 [x0,y0,mode0] 49 | byte gMouseCursX, gMouseCursY, gMouseCursMode ' mouse cursor 1 [x1,y1,mode1] (unused but required for VGA driver) 50 | 51 | long gVideoBufferPtr ' holds the address of the video buffer passed back from the VGA driver 52 | 53 | 54 | OBJ 55 | 56 | acia : "acia_rc2014" 57 | term : "terminal_ftdi" 58 | 59 | 60 | PUB start | i 61 | 62 | 'start the serial terminal 63 | term.start (115200) 64 | term.clear ' clear terminal 65 | term.str (string ($0D,"UX Module Initialising...",$0D)) 66 | 67 | 'start the ACIA interface 68 | acia.start (PORT_80) 69 | 70 | 'echo keystrokes in hex 71 | repeat 72 | if term.rxCheck 73 | acia.tx ( term.charIn ) 74 | if acia.rxCheck 75 | term.char ( acia.rx ) 76 | 77 | 78 | {{ 79 | +------------------------------------------------------------------------------------------------------------------------------+ 80 | | TERMS OF USE: MIT License | 81 | +------------------------------------------------------------------------------------------------------------------------------+ 82 | |Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation | 83 | |files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, | 84 | |modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software| 85 | |is furnished to do so, subject to the following conditions: | 86 | | | 87 | |The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.| 88 | | | 89 | |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 90 | |WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | 91 | |COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 92 | |ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 93 | +------------------------------------------------------------------------------------------------------------------------------+ 94 | }} -------------------------------------------------------------------------------- /docs/FT800 Programmers Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/FT800 Programmers Guide.pdf -------------------------------------------------------------------------------- /docs/MC6850.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/MC6850.pdf -------------------------------------------------------------------------------- /docs/P8X32A-Web-PropellerManual-v1.2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/P8X32A-Web-PropellerManual-v1.2.pdf -------------------------------------------------------------------------------- /docs/Propeller Quick Reference v1.7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/Propeller Quick Reference v1.7.pdf -------------------------------------------------------------------------------- /docs/RC2014_UX_MODULE_DTR.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/RC2014_UX_MODULE_DTR.JPG -------------------------------------------------------------------------------- /docs/RC2014_UX_MODULE_PREPRODUCTION.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/RC2014_UX_MODULE_PREPRODUCTION.JPG -------------------------------------------------------------------------------- /docs/RC2014_UX_MODULE_PRODUCTION.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/RC2014_UX_MODULE_PRODUCTION.JPG -------------------------------------------------------------------------------- /docs/RC2014_UX_MODULE_PRODUCTION_BOARD.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/RC2014_UX_MODULE_PRODUCTION_BOARD.JPG -------------------------------------------------------------------------------- /docs/RC2014_UX_MODULE_PROGAM_STATE.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/RC2014_UX_MODULE_PROGAM_STATE.JPG -------------------------------------------------------------------------------- /docs/RC2014_UX_MODULE_PROTOTYPE.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/RC2014_UX_MODULE_PROTOTYPE.JPG -------------------------------------------------------------------------------- /docs/RC2014_UX_MODULE_RUN_STATE.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/docs/RC2014_UX_MODULE_RUN_STATE.JPG -------------------------------------------------------------------------------- /pcb/24LC256.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/24LC256.pdf -------------------------------------------------------------------------------- /pcb/24LC512.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/24LC512.pdf -------------------------------------------------------------------------------- /pcb/ENG_CD_2311586_D.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/ENG_CD_2311586_D.pdf -------------------------------------------------------------------------------- /pcb/ENG_CD_5749265_P.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/ENG_CD_5749265_P.pdf -------------------------------------------------------------------------------- /pcb/MC74HC4078D.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/MC74HC4078D.pdf -------------------------------------------------------------------------------- /pcb/P8X32A-Propeller-Datasheet-v1.4.0_0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/P8X32A-Propeller-Datasheet-v1.4.0_0.pdf -------------------------------------------------------------------------------- /pcb/RC2014_UX_MODULE_BRD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/RC2014_UX_MODULE_BRD.png -------------------------------------------------------------------------------- /pcb/RC2014_UX_MODULE_ListByParts.csv: -------------------------------------------------------------------------------- 1 | Part,Value,Package,Description,Part Num 2 | C1,100n,C025-025X050,"CAPACITOR, European symbol",* 3 | C2,100n,C025-025X050,"CAPACITOR, European symbol",* 4 | C3,100n,C025-025X050,"CAPACITOR, European symbol",* 5 | C4,100n,C025-025X050,"CAPACITOR, European symbol",* 6 | C5,100n,C025-025X050,"CAPACITOR, European symbol",* 7 | C6,100n,C025-025X050,"CAPACITOR, European symbol",* 8 | C7,100p,C0805,"CAPACITOR, European symbol",* 9 | C8,100p,C0805,"CAPACITOR, European symbol",* 10 | C9,100p,C0805,"CAPACITOR, European symbol",* 11 | C10,100p,C0805,"CAPACITOR, European symbol",* 12 | C11,100p,C0805,"CAPACITOR, European symbol",* 13 | C12,200p,C0805,"CAPACITOR, European symbol",* 14 | C13,200p,C0805,"CAPACITOR, European symbol",* 15 | C14,100p,C0805,"CAPACITOR, European symbol",* 16 | C15,100p,C0805,"CAPACITOR, European symbol",* 17 | C16,200p,C0805,"CAPACITOR, European symbol",* 18 | C17,100u,CPOL-RADIAL-100UF-25V,Capacitor Polarized,* 19 | D1,1N4148DO35-7,DO35-7,DIODE,* 20 | D2,1N4148DO35-7,DO35-7,DIODE,* 21 | D3,1N4148DO35-7,DO35-7,DIODE,* 22 | FTDI_BASIC,FTDI_BASICPTH,FTDI_BASIC,FTDI Basic: 3.3V and 5V,* 23 | IC1,P8X32A-D40,DIL40,8-Cog Multiprocessor Microcontroller,P8X32A-D40 24 | IC2,24LC256P,DIL8,Serial EEPROM,24LC256-E/P 25 | IC3,M74HC4078B1R,DIP254P762X510-14,8-INPUT NOR/OR GATE,M74HC4078B1R 26 | IC4,TPS7333QP,P8_TEX,,* 27 | OSC1,7.3728MHz,DIL08-4,CRYSTAL RESONATOR,* 28 | PS/2,PS/2,M_DIN6,,* 29 | R1,3k3,R0805,,* 30 | R2,3k3,R0805,,* 31 | R3,3k3,R0805,,* 32 | R4,3k3,R0805,,* 33 | R5,3k3,R0805,,* 34 | R7,3k3,R0805,,* 35 | R8,3k3,R0805,,* 36 | R9,3k3,R0805,,* 37 | R10,3k3,R0805,,* 38 | R11,3k3,R0805,,* 39 | R12,3k3,R0805,,* 40 | R13,3k3,R0805,,* 41 | R14,3k3,R0805,,* 42 | R15,3k3,R0805,,* 43 | R16,3k3,R0805,,* 44 | R17,10k,R0207_7,,* 45 | R18,100,R0207_7,,* 46 | R19,100,R0207_7,,* 47 | R20,10k,R0207_7,,* 48 | R21,10k,R0207_7,,* 49 | R22,270 1%,R0207_7,,* 50 | R23,270 1%,R0207_7,,* 51 | R24,560 1%,R0207_7,,* 52 | R25,270 1%,R0207_7,,* 53 | R26,560 1%,R0207_7,,* 54 | R27,270 1%,R0207_7,,* 55 | R28,560 1%,R0207_7,,* 56 | R29,270 1%,R0207_7,,* 57 | R30,130 1%,R0207_7,,* 58 | R31,130 1%,R0207_7,,* 59 | R32,130 1%,R0207_7,,* 60 | R33,3k3,R0805,,* 61 | R34,3k3,R0805,,* 62 | VGA,CON-DSUB-15-VGA,181-015-212-171,NORCOMP's High Density 90° PC Mount D-Sub Connector,* 63 | -------------------------------------------------------------------------------- /pcb/RC2014_UX_MODULE_ListByValues.csv: -------------------------------------------------------------------------------- 1 | Qty,Value,Part Num,Package,Parts 2 | 3,1N4148DO35-7,*,DO35-7,"D1, D2, D3" 3 | 17,3k3,*,R0805,"R1, R2, R3, R4, R5, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R33, R34" 4 | 1,7.3728MHz (5MHz),*,DIL08-4,OSC1 5 | 7,100p,*,C0805,"C7, C8, C9, C10, C11, C14, C15" 6 | 3,200p,*,C0805,"C12, C13, C16" 7 | 3,10k,*,R0207_7,"R17, R20, R21" 8 | 1,24LC256P,24LC256-E/P,DIL8,IC2 9 | 2,100,*,R0207_7,"R18, R19" 10 | 6,100n,*,C025-025X050,"C1, C2, C3, C4, C5, C6" 11 | 1,100u,*,CPOL-RADIAL-100UF-25V,C17 12 | 3,130 1%,*,R0207_7,"R30, R31, R32" 13 | 5,270 1%,*,R0207_7,"R22, R23, R25, R27, R29" 14 | 3,560 1%,*,R0207_7,"R24, R26, R28" 15 | 1,CON-DSUB-15-VGA,*,181-015-212-171,VGA 16 | 1,FTDI_BASICPTH,*,FTDI_BASIC,FTDI_BASIC 17 | 1,M74HC4078B1R,M74HC4078B1R,DIP254P762X510-14,IC3 18 | 1,P8X32A-D40,P8X32A-D40,DIL40,IC1 19 | 1,PS/2,*,M_DIN6,PS/2 20 | 1,TPS7333QP,*,P8_TEX,IC4 21 | -------------------------------------------------------------------------------- /pcb/RC2014_UX_MODULE_NAMES.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/RC2014_UX_MODULE_NAMES.png -------------------------------------------------------------------------------- /pcb/RC2014_UX_MODULE_PRODUCTION.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/RC2014_UX_MODULE_PRODUCTION.zip -------------------------------------------------------------------------------- /pcb/RC2014_UX_MODULE_SCH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/RC2014_UX_MODULE_SCH.png -------------------------------------------------------------------------------- /pcb/RC2014_UX_MODULE_VALUES.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/RC2014_UX_MODULE_VALUES.png -------------------------------------------------------------------------------- /pcb/TPS7333.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/TPS7333.pdf -------------------------------------------------------------------------------- /pcb/ecs-2100x.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/ecs-2100x.pdf -------------------------------------------------------------------------------- /pcb/prototype/RC2014 UX MODULE BRD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/prototype/RC2014 UX MODULE BRD.png -------------------------------------------------------------------------------- /pcb/prototype/RC2014 UX MODULE SCH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/prototype/RC2014 UX MODULE SCH.png -------------------------------------------------------------------------------- /pcb/prototype/RC2014 UX MODULE VALUES.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/prototype/RC2014 UX MODULE VALUES.png -------------------------------------------------------------------------------- /pcb/prototype/RC2014_UX_MODULE.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feilipu/ux_module/569cd0751059cf53f4791f6414465df461989e4a/pcb/prototype/RC2014_UX_MODULE.pdf -------------------------------------------------------------------------------- /serial_dtr.py: -------------------------------------------------------------------------------- 1 | # To reset the Propeller, without unplugging the FTDI interface, then this DTR toogle tool can be used. 2 | 3 | import serial 4 | 5 | path = '/dev/ttyUSB0' 6 | baud = 115200 7 | 8 | # Open serial port 9 | ser = serial.Serial(path, baud) 10 | 11 | if(ser.isOpen() == False): 12 | print("Serial port open failed.\n"); 13 | exit; 14 | 15 | ser.setDTR(True); 16 | ser.setDTR(False); 17 | ser.close(); 18 | 19 | -------------------------------------------------------------------------------- /serial_tool.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import serial 3 | 4 | from time import sleep 5 | 6 | path = '/dev/ttyUSB0' 7 | baud = 115200 8 | 9 | # OPTION A 10 | # To disable /RESET after hangup 11 | # 12 | # import termios 13 | # with open(path) as f: 14 | # attrs = termios.tcgetattr(f) 15 | # attrs[2] = attrs[2] & ~termios.HUPCL 16 | # termios.tcsetattr(f, termios.TCSAFLUSH, attrs) 17 | 18 | # OPTION B 19 | # To disable /RESET after hangup 20 | # 21 | # import os 22 | # os.system("stty -F /dev/ttyUSB0 -hupcl") 23 | 24 | # OPTION C 25 | # Disconnect the GRN pin from the FTDI interface 26 | 27 | 28 | # Open serial port 29 | ser = serial.Serial(path, baud, dsrdtr=False) 30 | 31 | # Optionally check characteristics of serial port 32 | # print(ser) 33 | 34 | for line in sys.stdin: 35 | 36 | for ch in line: 37 | ser.write( ch ); 38 | 39 | ser.write('\r'); 40 | ser.flush(); 41 | sleep(0.01); 42 | 43 | ser.close() 44 | sys.exit() 45 | -------------------------------------------------------------------------------- /src/i2c.spin: -------------------------------------------------------------------------------- 1 | {{ 2 | i2cDriver. Provide bus-level and chip-level methods for I2C bus communication. 3 | Erlend Fj. 2015, 2016 4 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 5 | 6 | Supports standard 7 bit chip addressing, and both 8bit, 16bit, and 32bit register addressing. Use of 32bit is rare. 7 | Assumes the caller uses the chip address 7 bit format, onto which a r/w bit is added by the code before being transmitted. 8 | Signalling 'Open Collector Style' is achieved by setting pins OUTA := 0 permanent, and then manipulate on DIRA to either 9 | float the output, i.e. let PU resistor pull up to '1' -or- unfloat the output (which was set to 0) to bring it down to '0' 10 | 11 | Revisions: 12 | - Changed DAT assignment of scl and sda pins 13 | - Added BusInitialized flag 14 | - Added object instance identifier 15 | - Added isBusy 16 | - Added self-demo PUB Main 17 | 18 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 19 | }} 20 | { 21 | Acknowledgements: I have mainly built upon the work of Jon "JonnyMac" McPhalen 22 | 23 | ======================================================================================================================================================================= 24 | 25 | 26 | Propeller 27 | +-------------+ 28 | | +-------+ 3.3V +------------------------------------------------------// -----------------------------------+ 29 | | | | | | | | | | 30 | | | | | +-----------+ +-----------+ +-----------+ | | 31 | | | | | | V+ | | V+ | | V+ | | | 32 | | master | | + | | | | | | + | 33 | | | | 4k7 | Chip/slave| | Chip/slave| | Chip/slave| 4k7 | 34 | | | + + Pull-up | | | | | | + | 35 | | | 4k7 | |SDA SCL GND| |SDA SCL GND| |SDA SCL GND| | + 36 | | | + | +-----------+ +-----------+ +-----------+ | 4k7 37 | | | | | | | | | | | | | | | + 38 | | | | | | | | | | | | | | | | 39 | | | | | | | | | | | | | | | | 40 | | PINsda +-----------------------------------------------------------------------// -------------------------------+ | 41 | | | | I2C Bus | | | | | | | 42 | | PINscl +-----------------------------------------------------------------------// -----------------------------------+ 43 | | | | | | 44 | | GND +-----------------------------------------------------------------------// ----------------------+ 45 | | | 46 | +-------------+ 47 | 48 | About I2C 49 | --------- 50 | Both the SCL and the SDA line needs to be pulled up by p-u resistors. Value not critical for such slow speeds that Spin can do, but should be in the order of 1k-47k. 51 | With long lines have p-u resistors at each node to reduce noise or interference. 52 | 53 | REF: 54 | http://www.8051projects.net/wiki/I2C_TWI_Tutorial 55 | http://i2c.info/i2c-bus-specification 56 | 57 | ======================================================================================================================================================================= 58 | } 59 | 60 | CON 61 | 62 | mSec = 117965 ' ticks in 1ms = 7,372,800 * 16 xin * pll / 1_000 63 | uSec = 118 ' ticks in 1us = 7,372,800 * 16 xin * pll / 1_000_000 64 | 65 | CON 66 | 67 | ACK = 0 'signals ready for more 68 | NAK = 1 'signals not ready for more 69 | 70 | CON 71 | 72 | SCL_PIN = 29 'This is reversed from standard pinout, to ensure that only the EEPROM 73 | SDA_PIN = 28 'appears on the I2C bus during boot process. Ensures no address conflicts. 74 | 75 | DAT 76 | PINscl LONG 0 'Use DAT variable to make the assignment stick for later calls to the object, and optionally 77 | PINsda LONG 0 'assign to default pin numbers. Use init( ) to change at runtime. Best for many chips same one bus. 78 | 'and assign to default pin numbers Use init( ) to change at runtime 79 | 80 | BusInitialized LONG FALSE 'If this is not desired, change from defining PINmosi etc. as DAT to VAR, and 81 | 'assign value to them in init( ) by means of 'PINmosi:= _PINmosi' etc. instead. 82 | 'Best when many busses. 83 | 84 | ThisObjectInstance LONG 1 'Change to separate object loads for different physical buses 85 | 86 | fit 87 | 88 | 89 | PUB init(_PINscl, _PINsda) 90 | 91 | 'INITIATION METHOD 92 | '================================================================================================================================================= 93 | 94 | LONG[@PINscl]:= _PINscl 'Copy pin into DAT where it will survive 95 | LONG[@PINsda]:= _PINsda 'into later calls to this object 96 | 97 | DIRA[PINscl] := 0 'Float output 98 | OUTA[PINscl] := 0 'and set to 0 99 | DIRA[PINsda] := 0 'to simulate open collector i/o (i.e. pull-up resistors required) 100 | reset 'Do bus reset to clear any chips' activity 101 | LONG[@BusInitialized]:= TRUE 'Keep tally of initialization 102 | 103 | 104 | PUB isInitialized 105 | 106 | RETURN BusInitialized 107 | 108 | 109 | 'CHIP LEVEL METHODS - calls BUS LEVEL METHODS below, encapsulates the details of the workings of the bus 110 | '================================================================================================================================================= 111 | 'Write 112 | 113 | 'Byte (8bit) 114 | 115 | PUB writeByteA8(ChipAddr, RegAddr, Value) 'Write a byte to specified chip and 8bit register address 116 | 117 | IF callChip(ChipAddr << 1)== ACK 'Shift left 1 to add on the read/write bit, default 0 (write) 118 | writeBus(RegAddr) 119 | writeBus(Value) 120 | stop 121 | 122 | 123 | PUB writeByteA16(ChipAddr, RegAddr, Value) 'Write a byte to specified chip and 16bit register address 124 | 125 | IF callChip(ChipAddr << 1)== ACK 'Shift left 1 to add on the read/write bit, default 0 (write) 126 | writeBus(RegAddr.BYTE[1]) 'MSB 127 | writeBus(RegAddr.BYTE[0]) 'LSB 128 | writeBus(Value) 129 | stop 130 | 131 | 132 | 'Word (16bit) 133 | 134 | PUB writeWordA8(ChipAddr, RegAddr, Value) 'Write a Word to specified chip and 8bit register address 135 | 136 | IF callChip(ChipAddr << 1)== ACK 'Shift left 1 to add on the read/write bit, default 0 (write) 137 | writeBus(RegAddr) 138 | writeBus(Value.BYTE[1]) 'MSB 139 | writeBus(Value.BYTE[0]) 'LSB 140 | stop 141 | 142 | 143 | PUB writeWordA16(ChipAddr, RegAddr, Value) 'Write a Word to specified chip and 16bit register address 144 | 145 | IF callChip(ChipAddr << 1)== ACK 'Shift left 1 to add on the read/write bit, default 0 (write) 146 | writeBus(RegAddr.BYTE[1]) 'MSB 147 | writeBus(RegAddr.BYTE[0]) 'LSB 148 | writeBus(Value.BYTE[1]) 'MSB 149 | writeBus(Value.BYTE[0]) 'LSB 150 | stop 151 | 152 | 153 | 'Long (32bit) 154 | 155 | PUB writeLongA8(ChipAddr, RegAddr, Value) 'Write a Long to specified chip and 8bit register address 156 | 157 | IF callChip(ChipAddr << 1)== ACK 'Shift left 1 to add on the read/write bit, default 0 (write) 158 | writeBus(RegAddr) 159 | writeBus(Value.BYTE[3]) 'MSB 160 | writeBus(Value.BYTE[2]) 'NMSB 161 | writeBus(Value.BYTE[1]) 'NLSB 162 | writeBus(Value.BYTE[0]) 'LSB 163 | stop 164 | 165 | 166 | PUB writeLongA16(ChipAddr, RegAddr, Value) 'Write a Long to specified chip and 16bit register address 167 | 168 | IF callChip(ChipAddr << 1)== ACK 'Shift left 1 to add on the read/write bit, default 0 (write) 169 | writeBus(RegAddr.BYTE[1]) 'MSB 170 | writeBus(RegAddr.BYTE[0]) 'LSB 171 | writeBus(Value.BYTE[3]) 'MSB 172 | writeBus(Value.BYTE[2]) 'NMSB 173 | writeBus(Value.BYTE[1]) 'NLSB 174 | writeBus(Value.BYTE[0]) 'LSB 175 | stop 176 | 177 | 178 | ' Special ------------not debugged, written in attempt to communicate with adafruit oled ------------------------------------------------------------------------- 179 | 180 | PUB writeByteDirect(ChipAddr, FlagByte, OneByte) 'Write direct, flagbyte determines if command, parameter or data, register addressing not used 181 | 182 | IF callChip(ChipAddr << 1)== ACK 'Shift left 1 to add on the read/write bit, default 0 (write) 183 | writeBus(FlagByte) 'FlagByte determines if data is received as command, parameter or data 184 | writeBus(OneByte) 185 | stop 186 | 187 | 188 | PUB writeBlockDirect(ChipAddr, FlagByte, OneByte, begin_end) 'Write direct, flagbyte must signal 'data write' begin_end= 1:begin, 0:continue, -1:end 189 | IF begin_end== 1 190 | IF callChip(ChipAddr << 1)== ACK 'Shift left 1 to add on the read/write bit, default 0 (write) 191 | writeBus(FlagByte) 'FlagByte determines if data is received as command, parameter or data 192 | writeBus(OneByte) 'First byte of data 193 | ELSEIF begin_end== 0 194 | writeBus(FlagByte) 195 | writeBus(OneByte) 'A number of bytes of data 196 | ELSEIF begin_end== -1 197 | writeBus(FlagByte) 198 | writeBus(OneByte) 'Last byte of data 199 | stop 200 | 201 | 202 | 203 | 'Read------------------------------------------------------------------------------------------------------ 204 | 'Byte 205 | 206 | PUB readByteA8(ChipAddr, RegAddr) | Value 'Read a byte from specified chip and 8bit register address 207 | 208 | IF callChip(ChipAddr << 1)== ACK 'Check if chip responded 209 | writeBus(RegAddr) 210 | start 'Restart for reading 211 | writeBus(ChipAddr << 1 | 1 ) 'address again, but with the read/write bit set to 1 (read) 212 | Value:= readBus(NAK) 213 | stop 214 | RETURN Value 215 | ELSE 216 | RETURN FALSE 217 | 218 | 219 | PUB readByteA16(ChipAddr, RegAddr) | Value 'Read a byte from specified chip and 16bit register address 220 | 221 | IF callChip(ChipAddr << 1)== ACK 'Check if chip responded 222 | writeBus(RegAddr.BYTE[1]) 'MSB 223 | writeBus(RegAddr.BYTE[0]) 'LSB 224 | start 'Restart for reading 225 | writeBus(ChipAddr << 1 | 1 ) 'address again, but with the read/write bit set to 1 (read) 226 | Value:= readBus(NAK) 227 | stop 228 | RETURN Value 229 | ELSE 230 | RETURN FALSE 231 | 232 | 'Word 233 | 234 | PUB readWordA8(ChipAddr, RegAddr) | Value 'Read a Word from specified chip and 8bit register address 235 | 236 | IF callChip(ChipAddr << 1)== ACK 'Check if chip responded 237 | writeBus(RegAddr) 238 | start 'Restart for reading 239 | writeBus(ChipAddr << 1 | 1 ) 'address again, but with the read/write bit set to 1 (read) 240 | Value.BYTE[3]:= 0 'clear the rubbish 241 | Value.BYTE[2]:= 0 'clear the rubbish 242 | Value.BYTE[1]:= readBus(ACK) 'MSB 243 | Value.BYTE[0]:= readBus(NAK) 'LSB 244 | stop 245 | RETURN Value 246 | ELSE 247 | RETURN FALSE 248 | 249 | 250 | PUB readWordA16(ChipAddr, RegAddr) | Value 'Read a Word from specified chip and 16bit register address 251 | 252 | IF callChip(ChipAddr << 1)== ACK 'Check if chip responded 253 | writeBus(RegAddr.BYTE[1]) 'MSB 254 | writeBus(RegAddr.BYTE[0]) 'LSB 255 | start 'Restart for reading 256 | writeBus(ChipAddr << 1 | 1 ) 'address again, but with the read/write bit set to 1 (read) 257 | Value.BYTE[3]:= 0 'clear the rubbish 258 | Value.BYTE[2]:= 0 'clear the rubbish 259 | Value.BYTE[1]:= readBus(ACK) 'MSB 260 | Value.BYTE[0]:= readBus(NAK) 'LSB 261 | stop 262 | RETURN Value 263 | ELSE 264 | RETURN FALSE 265 | 266 | 267 | 'Long 268 | 269 | PUB readLongA8(ChipAddr, RegAddr) | Value 'Read a Long from specified chip and 8bit register address 270 | 271 | IF callChip(ChipAddr << 1)== ACK 'Check if chip responded 272 | writeBus(RegAddr) 273 | start 'Restart for reading 274 | writeBus(ChipAddr << 1 | 1 ) 'address again, but with the read/write bit set to 1 (read) 275 | Value.BYTE[3]:= readBus(ACK) 'MSB 276 | Value.BYTE[2]:= readBus(ACK) 'NMSB 277 | Value.BYTE[1]:= readBus(ACK) 'NLSB 278 | Value.BYTE[0]:= readBus(NAK) 'LSB 279 | stop 280 | RETURN Value 281 | ELSE 282 | RETURN FALSE 283 | 284 | 285 | PUB readLongA16(ChipAddr, RegAddr) | Value 'Read a Long from specified chip and 16bit register address 286 | 287 | IF callChip(ChipAddr << 1)== ACK 'Check if chip responded 288 | writeBus(RegAddr.BYTE[1]) 'MSB 289 | writeBus(RegAddr.BYTE[0]) 'LSB 290 | start 'Restart for reading 291 | writeBus(ChipAddr << 1 | 1 ) 'address again, but with the read/write bit set to 1 (read) 292 | Value.BYTE[3]:= readBus(ACK) 'MSB 293 | Value.BYTE[2]:= readBus(ACK) 'NMSB 294 | Value.BYTE[1]:= readBus(ACK) 'NLSB 295 | Value.BYTE[0]:= readBus(NAK) 'LSB 296 | stop 297 | RETURN Value 298 | ELSE 299 | RETURN FALSE 300 | 301 | 302 | 'BUS LEVEL METHODS 303 | '============================================================================================================================================= 304 | PUB reset 'Do bus reset to clear any chips' activity 305 | 306 | OUTA[PINsda] := 0 'Float SDA 307 | REPEAT 9 308 | DIRA[PINscl] := 1 'Toggle SCL to clock out any remaining bits, maximum 8bits + acknak bit 309 | DIRA[PINscl] := 0 'or until 310 | IF (INA[PINsda]) 'SDA is released to go high by chip(s) 311 | QUIT 312 | 313 | 314 | PUB isBusy 315 | 316 | IF INA[PINsda]== 1 AND INA[PINscl]== 1 317 | RETURN FALSE 318 | ELSE 319 | RETURN TRUE 320 | 321 | 322 | PUB whoOnBus(ptrOnBusArr) | onbus, addr 'Fills an array with max 119 elements with addresses that get a response 323 | 'and writes how many is onbus to the 0th element 324 | onbus:= 1 325 | 326 | REPEAT addr FROM %0000_1000 TO %0111_0111 'Scan the entire address space, exept for reserved spaces 327 | IF callChip(addr << 1)== ACK 'If a chip acknowledges, 328 | LONG[ptrOnBusArr][onbus]:= addr 'put that address in the callers array 329 | LONG[ptrOnBusArr][0]:= onbus 'and update the total count of chips on the bus 330 | onbus++ 331 | IF onbus> 119 'until loop expires or maximum number of elements in the array is reached 332 | stop 333 | QUIT 334 | stop 'After each call send a stop signal to avoid confusion 335 | 336 | 337 | PUB callChip(ChipAddr) | acknak, t 'Address the chip until it acknowledges or timeout 338 | 339 | t:= CNT 'Set start time 340 | REPEAT 341 | start 'Prepare chips for responding 342 | acknak:= writeBus(ChipAddr) 'Address the chip 343 | IF CNT > t+ 10*mSec 'and break if timeout 344 | RETURN NAK 345 | UNTIL acknak == ACK 'or until it acknowledges 346 | RETURN ACK 347 | 348 | 349 | PUB start 'Check that no chip is holding down SCL, then signal 'start' 350 | 351 | DIRA[PINsda] := 0 352 | DIRA[PINscl] := 0 353 | WAITPEQ(|16)-(y2~>16)+1) 70 | 71 | PUB slopeCalc2(x1,x2,y1,y2) 72 | return ((x1-x2))/(y1-y2+1) 73 | 74 | PUB point(x,y,colors) 75 | box(x,y,x+1,y+1,colors) 76 | 77 | PUB line(x1,y1,x2,y2,colors) : ihead | tmp '' TODO: Add dedicated line shape type? 78 | if y1 > y2 79 | tmp := y1 80 | y1 := y2 81 | y2 := tmp 82 | 83 | tmp := x1 84 | x1 := x2 85 | x2 := tmp 86 | 87 | if y2bottomclip 88 | return 89 | 90 | putlink 91 | if (spaceleft -= constant(3*2)) < 0 92 | abort 12 93 | ihead:=head 94 | byte[ihead++]:=(-1) ' init sync to -1 95 | tmp := ihead++ ' shape type (set later) 96 | word[ihead]:=(y1.word[1]) ' start line 97 | ihead+=2 98 | word[ihead]:=(y2.word[1]+1) ' end line 99 | ihead+=2 100 | if y2.word[1] == y1.word[1] ' horizontal line 101 | if (spaceleft -= constant(3*2)) < 0 102 | abort 13 103 | byte[tmp]:=(SHP_BOX) 104 | 105 | if x1 < x2 106 | word[ihead]:=(x1~>16) 107 | ihead+=2 108 | word[ihead]:=(x2~>16) 109 | else 110 | word[ihead]:=(x2~>16) 111 | ihead+=2 112 | word[ihead]:=(x1~>16) 113 | ihead+=2 114 | word[ihead]:=(colors) 115 | ihead+=4 ' 2 + 2 unused 116 | else 117 | if (spaceleft -= constant(2*4 + 4*4 + 2*2 + 4)) < 0 118 | abort 14 119 | byte[tmp]:=(SHP_TRAPSTACK) 120 | ihead+= constant(2*4) ' scratch 121 | tmp := slopeCalc(x2,x1,y2,y1) 122 | if x1 =< x2 123 | long[ihead]:=(x1) 124 | ihead+=4 125 | long[ihead]:=(x1+tmp+$10000) 126 | else 127 | long[ihead]:=(x1+tmp-$10000) 128 | ihead+=4 129 | long[ihead]:=(x1) 130 | ihead+=4 131 | 132 | word[ihead]:=((y2.word[1])-(y1.word[1])+1) 133 | ihead+=2 134 | word[ihead]:=(colors) 135 | ihead+=2 136 | 137 | long[ihead]:=(tmp) 138 | ihead+=4 139 | long[ihead]:=(tmp) 140 | ihead+=4 141 | 142 | head:=ihead 143 | 144 | 145 | PUB line_triangle(x1,y1,x2,y2,x3,y3,colors) 146 | line(x1,y1,x2,y2,colors) 147 | line(x1,y1,x3,y3,colors) 148 | line(x2,y2,x3,y3,colors) 149 | 150 | 151 | PUB line_polygon(polyptr,vcount,colors) | i,px,py 152 | 153 | px := long[polyptr][(vcount<<1)-2] 154 | py := long[polyptr][(vcount<<1)-1] 155 | repeat i from 0 to vcount-1 156 | line(px,py,px := long[polyptr][(i<<1)],py := long[polyptr][(i<<1)+1],colors) 157 | 158 | 159 | PUB box(x1,y1,x2,y2,colors) : ihead 160 | 161 | if y2<(topclip~>16) or y1=>(bottomclip~>16) or x2<(leftclip~>16) or x1=>(rightclip~>16) 162 | return 163 | 164 | putlink 165 | if (spaceleft -= constant(1+1+2+2+2+2+2)) < 0 166 | abort 11 167 | ihead:=head 168 | byte[ihead++]:=(-1) ' init sync to -1 169 | byte[ihead++]:=(SHP_BOX) ' type 170 | word[ihead]:=(y1) ' start line 171 | ihead+=2 172 | word[ihead]:=(y2) ' end line 173 | ihead+=2 174 | word[ihead]:=(x1) 175 | ihead+=2 176 | word[ihead]:=(x2) 177 | ihead+=2 178 | word[ihead]:=(colors) 179 | head:=(ihead+=4) ' 2 unused!!! 180 | 181 | 182 | PUB triangle(x1,y1,x2,y2,x3,y3,colors) : ihead | tmp,tmp2,tmp3 183 | 184 | if y1 > y2 185 | tmp := y1 186 | y1 := y2 187 | y2 := tmp 188 | 189 | tmp := x1 190 | x1 := x2 191 | x2 := tmp 192 | 193 | if y1 > y3 194 | tmp := y1 195 | y1 := y3 196 | y3 := tmp 197 | 198 | tmp := x1 199 | x1 := x3 200 | x3 := tmp 201 | 202 | if y2 > y3 203 | tmp := y2 204 | y2 := y3 205 | y3 := tmp 206 | 207 | tmp := x2 208 | x2 := x3 209 | x3 := tmp 210 | 211 | if y3bottomclip OR (y2.word[1] == y1.word[1] AND y2.word[1] == y3.word[1]) 212 | return 'reject offscreen/degenerate triangle 213 | 214 | putlink 215 | if (spaceleft -= constant(1+1+2+2 + 2*4)) < 0 216 | abort 7 217 | ihead:=head 218 | byte[ihead++]:=(-1) ' init sync to -1 219 | byte[ihead++]:=(SHP_TRAPSTACK) ' type 220 | word[ihead]:=(y1.word[1]) ' start line 221 | ihead+=2 222 | word[ihead]:=(y3.word[1]+1) ' end line 223 | ihead+=2 224 | ihead+=(constant(2*4)) ' scratch 225 | 'head:=ihead 226 | 227 | if y2.word[1] == y3.word[1] ' bottom flat? 228 | 229 | if (spaceleft -= constant(4*4 + 2*2)) < 0 230 | abort 8 231 | 'pst.str(string("bottom flat",13)) 232 | tmp := slopeCalc(x3,x1,y3,y1) 233 | tmp2:= slopeCalc(x2,x1,y2,y1) 234 | if x2 > x3 235 | long[ihead]:=(x1+(tmp<#0)) 236 | ihead+=4 237 | long[ihead]:=(x1+(tmp2#>0)) 238 | else 239 | long[ihead]:=(x1+(tmp2<#0)) 240 | ihead+=4 241 | long[ihead]:=(x1+(tmp#>0)) 242 | ihead+=4 243 | 244 | word[ihead]:=((y3.word[1])-(y1.word[1])+1) 245 | ihead+=2 246 | word[ihead]:=(colors) 247 | ihead+=2 248 | 249 | if x2 > x3 250 | long[ihead]:=(tmp) 251 | ihead+=4 252 | long[ihead]:=(tmp2) 253 | else 254 | long[ihead]:=(tmp2) 255 | ihead+=4 256 | long[ihead]:=(tmp) 257 | 258 | elseif y1.word[1] == y2.word[1] ' top flat? 259 | if (spaceleft -= constant(4*4 + 2*2)) < 0 260 | abort 9 261 | 'pst.str(string("top flat",13)) 262 | tmp := slopeCalc(x3,x2,y3,y2) 263 | tmp2:= slopeCalc(x3,x1,y3,y1) 264 | if x1 > x2 265 | long[ihead]:=(x2+(tmp<#0)) 266 | ihead+=4 267 | long[ihead]:=(x1+(tmp2#>0)) 268 | else 269 | long[ihead]:=(x1+(tmp2<#0)) 270 | ihead+=4 271 | long[ihead]:=(x2+(tmp#>0)) 272 | ihead+=4 273 | 274 | word[ihead]:=((y3.word[1])-(y1.word[1])+1) 275 | ihead+=2 276 | word[ihead]:=(colors) 277 | ihead+=2 278 | 279 | 280 | if x1 > x2 281 | long[ihead]:=(tmp) 282 | ihead+=4 283 | long[ihead]:=(tmp2) 284 | else 285 | long[ihead]:=(tmp2) 286 | ihead+=4 287 | long[ihead]:=(tmp) 288 | 289 | else 290 | if (spaceleft -= constant(6*4 + 4*2)) < 0 291 | abort 10 292 | 'pst.str(string("other",13)) 293 | 294 | tmp := slopeCalc(x3,x1,y3,y1) ' long slope 295 | tmp2 := slopeCalc(x2,x1,y2,y1)' short slope 296 | if tmp2 > tmp 297 | long[ihead]:=(x1+(tmp<#0)) 298 | ihead+=4 299 | long[ihead]:=(x1+(tmp2#>0)) 300 | ihead+=4 301 | 302 | word[ihead]:=((y2.word[1])-(y1.word[1])) 303 | ihead+=2 304 | 'putword($CCCC) 305 | word[ihead]:=(colors) 306 | ihead+=2 307 | 308 | long[ihead]:=(tmp) 309 | ihead+=4 310 | long[ihead]:=(tmp2) 311 | else 312 | long[ihead]:=(x1+(tmp2<#0)) 313 | ihead+=4 314 | long[ihead]:=(x1+(tmp#>0)) 315 | ihead+=4 316 | 317 | word[ihead]:=((y2.word[1])-(y1.word[1])) 318 | ihead+=2 319 | 'putword($CCCC) 320 | word[ihead]:=(colors) 321 | ihead+=2 322 | 323 | long[ihead]:=(tmp2) 324 | ihead+=4 325 | long[ihead]:=(tmp) 326 | ihead+=4 327 | 328 | word[ihead]:=((y3.word[1])-(y2.word[1])+1) 329 | ihead+=2 330 | 'putword($4C4C) 331 | word[ihead]:=(colors) 332 | ihead+=2 333 | 334 | tmp3 := slopeCalc(x3,x2,y3,y2) 335 | if tmp2 > tmp 336 | long[ihead]:=(tmp) 337 | ihead+=4 338 | long[ihead]:=(tmp3) 339 | else 340 | long[ihead]:=(tmp3) 341 | ihead+=4 342 | long[ihead]:=(tmp) 343 | 344 | head:=(ihead+=4) 345 | 346 | 347 | PUB polygon(polyptr,vcount,colors,ccw) : ihead | tmp,lefti,righti,ybottom,ytop,topi,bottomi,leftx,rightx,lefty,righty,topleftx,toprightx,toplefty,toprighty,leftslope,rightslope,topptr,stepy 348 | 349 | if vcount < 3 350 | return -2 ' degenerate poly 351 | 352 | ytop := posx 353 | ybottom:=negx 354 | topi := 0 355 | 356 | '' find topmost vertex 357 | repeat lefti from 0 to vcount-1 358 | if (tmp:=long[polyptr+(lefti<<3)][1]~>16) < ytop 359 | ytop := tmp 360 | topi := lefti 361 | topleftx:=toprightx:= long[polyptr+(lefti<<3)] 362 | elseif tmp == ytop 363 | tmp:=long[polyptr+(lefti<<3)] 364 | topleftx <#=tmp 365 | toprightx#>=tmp 366 | 367 | '' find bottommost vertex 368 | lefti:=topi 369 | repeat vcount 370 | if ++lefti=>vcount 371 | lefti-=vcount 372 | if (tmp:=long[polyptr+(lefti<<3)][1]~>16) => ybottom 373 | ybottom := tmp 374 | bottomi := lefti 375 | 376 | if ytop =>bottomclip~>16 OR ybottom < topclip~>16 377 | return -3 ' clip 378 | if ytop == ybottom 379 | return -4' degenerate poly 380 | 381 | '' if not given by caller, 382 | '' figure out chain direction (CW or CCW) and set ccw to 1 or -1 accordingly 383 | '' we do this by looking at the slopes coming off the topmost vertex 384 | ifnot ccw 385 | lefti := righti := topi 386 | if --lefti<0 387 | lefti+=vcount 388 | if ++righti=>vcount 389 | righti-=vcount 390 | leftslope := slopeCalc2(long[polyptr+(lefti<<3)],long[polyptr+(topi<<3)],long[polyptr+(lefti<<3)][1]~>16,ytop) 391 | rightslope := slopeCalc2(long[polyptr+(righti<<3)],long[polyptr+(topi<<3)],long[polyptr+(righti<<3)][1]~>16,ytop) 392 | ccw := (( ( leftslope > rightslope ) )<< 1)+1 393 | 394 | putlink 395 | if (spaceleft -= constant(1+1+2+2+(2*4)+4+4)) < 0 396 | abort 20 397 | ihead:=head 398 | byte[ihead++]:=(-1) ' init sync to -1 399 | byte[ihead++]:=(SHP_TRAPSTACK) ' type 400 | word[ihead]:=(ytop) ' start line 401 | ihead+=2 402 | word[ihead]:=(ybottom+1) ' end line 403 | ihead+=2 404 | ihead+=(constant(2*4)) 'scratch 405 | 406 | '' initialize top edges - slopes will be added on later 407 | topptr:=ihead 408 | long[ihead]:=(topleftx) 409 | ihead+=4 410 | long[ihead]:=(toprightx) 411 | ihead+=4 412 | 413 | '' find first left vertex 414 | lefti := topi 415 | repeat 416 | lefti-=ccw 417 | if lefti<0 418 | lefti+=vcount 419 | elseif lefti => vcount 420 | lefti-=vcount 421 | lefty:=long[polyptr+(lefti<<3)][1]~>16 422 | if lefty <> ytop 423 | quit 424 | 425 | '' find first right vertex 426 | righti := topi 427 | repeat 428 | righti+=ccw 429 | if righti<0 430 | righti+=vcount 431 | elseif righti => vcount 432 | righti-=vcount 433 | righty:=long[polyptr+(righti<<3)][1]~>16 434 | if righty <> ytop 435 | quit 436 | 437 | '' build trapezoid stack 438 | toplefty := toprighty := ytop 439 | leftslope:=rightslope:=negx 440 | repeat 441 | leftx := posx 442 | rightx:= negx 443 | 444 | if lefti<0 445 | lefti+=vcount 446 | elseif lefti => vcount 447 | lefti-=vcount 448 | if righti<0 449 | righti+=vcount 450 | elseif righti => vcount 451 | righti-=vcount 452 | 453 | '' find left vertex 454 | if leftslope==negx 455 | repeat 456 | leftx<#=long[polyptr+(lefti<<3)] 457 | lefty:=long[polyptr+(lefti<<3)][1]~>16 458 | if lefty == ybottom 459 | quit 460 | ' take all vertices on the same Y 461 | tmp := lefti-ccw 462 | if tmp<0 463 | tmp+=vcount 464 | elseif tmp => vcount 465 | tmp-=vcount 466 | if long[polyptr+(tmp<<3)][1]~>16 <> lefty 467 | quit 468 | lefti:=tmp 469 | 470 | '' find right vertex 471 | if rightslope==negx 472 | repeat 473 | rightx#>=long[polyptr+(righti<<3)] 474 | righty:=long[polyptr+(righti<<3)][1]~>16 475 | if righty == ybottom 476 | quit 477 | ' take all vertices on the same Y 478 | tmp := righti+ccw 479 | if tmp<0 480 | tmp+=vcount 481 | elseif tmp => vcount 482 | tmp-=vcount 483 | if long[polyptr+(tmp<<3)][1]~>16 <> righty 484 | quit 485 | righti:=tmp 486 | 487 | 'return lefti 488 | stepy:=lefty <# righty 489 | 'putword($FFF) 490 | if (spaceleft -= constant(2+2+4+4)) < 0 491 | abort 20 492 | word[ihead]:=(stepy-(toplefty <# toprighty)+((tmp := (stepy==ybottom))>>31)) ' trapezoid height 493 | ihead+=2 494 | word[ihead]:=(colors) 495 | ihead+=2 496 | 497 | '' re-calculate slopes if neccessary 498 | if leftslope == negx 499 | leftslope:=slopeCalc2(leftx,topleftx,lefty+(toplefty<>ytop AND toplefty<>ybottom),toplefty) 500 | topleftx:=leftx 501 | toplefty:=lefty 502 | if rightslope == negx 503 | rightslope:=slopeCalc2(rightx,toprightx,righty+(toprighty<>ytop AND toprighty<>ybottom),toprighty) 504 | toprightx:=rightx 505 | toprighty:=righty 506 | 507 | long[ihead]:=(leftslope) 508 | ihead+=4 509 | long[ihead]:=(rightslope) 510 | ihead+=4 511 | if topptr 512 | long[topptr]+=leftslope<#0 513 | long[topptr~][1]+=rightslope#>0 ' note the post-clear 514 | 515 | if lefty= topclip~>16 AND y < bottomclip~>16 529 | 530 | putlink 531 | if (spaceleft -= constant(1+1+2+2+ 1+1+ 2+2+2+2)) < 0 532 | abort 16 533 | ihead:=head 534 | byte[ihead++]:=(-1) ' init sync to -1 535 | byte[ihead++]:=(SHP_TEXT) ' type 536 | word[ihead]:=(y) ' start line 537 | ihead+=2 538 | word[ihead]:=(ystop) ' end line 539 | ihead+=2 540 | ihead++ ' unused byte 541 | byte[ihead++]:=(xscale<<5+(yscale&31)) ' scale 542 | word[ihead]:=(font) 543 | ihead+=2 544 | word[ihead]:=(str) 545 | ihead+=2 546 | word[ihead]:=(colors) 547 | ihead+=2 548 | word[ihead]:=(x) 549 | head:=(ihead+=4) ' 2 unused bytes ! 550 | 551 | PUB text_centered(x,y,xscale,yscale,str,font,colors) 552 | return text(x-((strsize(str)*9)<>1,y,xscale,yscale,str,font,colors) 553 | 554 | PUB text_ljust(x,y,xscale,yscale,str,font,colors) 555 | return text(x-((strsize(str)*9)< 0) 103 | directionState := ($FF << (8 * pinGroup)) 104 | videoState := (%0_01_1_0_0_000_00000000000_000_0_11111111 | (pinGroup << 9)) 105 | 106 | pixelClock := constant(20_000_000 / 2) 107 | frequencyState := 1 108 | 109 | repeat 32 110 | pixelClock <<= 1 111 | frequencyState <-= 1 112 | if(pixelClock => clkfreq) 113 | pixelClock -= clkfreq 114 | frequencyState += 1 115 | 116 | syncIndicatorAddress := statusLong 117 | cogNumber := cognew(@initialization, lineBuffers) 118 | result or= ++cogNumber 119 | 120 | 121 | PUB stop '' 3 Stack Longs 122 | 123 | '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 124 | '' // Shuts down the PIX driver running on a cog. 125 | '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 126 | 127 | if(cogNumber) 128 | cogstop(-1 + cogNumber~) 129 | 130 | 131 | DAT 132 | 133 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 134 | ' PIX Driver 135 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 136 | 137 | org 0 138 | 139 | ' //////////////////////Initialization///////////////////////////////////////////////////////////////////////////////////////// 140 | 141 | initialization mov vcfg, videoState ' Setup video hardware. 142 | mov frqa, frequencyState 143 | movi ctra, #%0_00001_101 ' PLL internal (video mode) VCO/4 144 | 145 | or dira, directionState ' Setup video output pins 146 | 147 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 148 | ' Active Video 149 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 150 | 151 | loop mov tilesCounter, #0 152 | 153 | tilesDisplay 154 | test tilesCounter, #7 wz 155 | if_z mov displayCounter, par ' Set/Reset tiles fill counter. 156 | mov tileCounter, #2 ' Set/Reset tile fill counter. 157 | 158 | wrlong tilesCounter, syncIndicatorAddress 159 | 160 | tileDisplay mov vscl, visibleScale ' Set/Reset the video scale. 161 | mov counter, #256/4 162 | 163 | ' //////////////////////Visible Video////////////////////////////////////////////////////////////////////////////////////////// 164 | 165 | videoLoop rdlong buffer, displayCounter ' Download new pixels. 166 | add displayCounter, #4 167 | 168 | or buffer, HVSyncColors ' Update display scanline. 169 | waitvid buffer, #%%3210 170 | 171 | djnz counter, #videoLoop ' Repeat. 172 | 173 | ' //////////////////////Invisible Video//////////////////////////////////////////////////////////////////////////////////////// 174 | 175 | mov vscl, invisibleScale ' Set/Reset the video scale. 176 | 177 | waitvid HSyncColors, syncPixels ' Horizontal Sync. 178 | 179 | ' //////////////////////Repeat///////////////////////////////////////////////////////////////////////////////////////////////// 180 | 181 | sub displayCounter, #256 ' Repeat line. 182 | djnz tileCounter, #tileDisplay 183 | 184 | add displayCounter, #256 ' Next line. 185 | add tilesCounter, #1 186 | cmp tilesCounter, #240 wc,wz 187 | if_b jmp #tilesDisplay 188 | 189 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 190 | ' Inactive Video 191 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 192 | 193 | ' //////////////////////Front Porch//////////////////////////////////////////////////////////////////////////////////////////// 194 | 195 | mov counter, #11 ' Set loop counter. 196 | wrlong FPorchStatus, syncIndicatorAddress 197 | 198 | frontPorch mov vscl, blankPixels ' Invisible lines. 199 | waitvid HSyncColors, #0 200 | 201 | mov vscl, invisibleScale ' Horizontal Sync. 202 | waitvid HSyncColors, syncPixels 203 | 204 | djnz counter, #frontPorch ' Repeat # times. 205 | 206 | ' //////////////////////Vertical Sync////////////////////////////////////////////////////////////////////////////////////////// 207 | 208 | mov counter, #2 ' Set loop counter. 209 | wrlong VSyncStatus, syncIndicatorAddress 210 | 211 | verticalSync mov vscl, blankPixels ' Invisible lines. 212 | waitvid VSyncColors, #0 213 | 214 | mov vscl, invisibleScale ' Vertical Sync. 215 | waitvid VSyncColors, syncPixels 216 | 217 | djnz counter, #verticalSync ' Repeat # times. 218 | 219 | ' //////////////////////Back Porch///////////////////////////////////////////////////////////////////////////////////////////// 220 | 221 | mov counter, #31 ' Set loop counter. 222 | wrlong BPorchStatus, syncIndicatorAddress 223 | 224 | backPorch mov vscl, blankPixels ' Invisible lines. 225 | waitvid HSyncColors, #0 226 | 227 | mov vscl, invisibleScale ' Horizontal Sync. 228 | waitvid HSyncColors, syncPixels ' 229 | 230 | djnz counter, #backPorch ' Repeat # times. 231 | 232 | ' //////////////////////Loop/////////////////////////////////////////////////////////////////////////////////////////////////// 233 | 234 | jmp #loop ' Loop. 235 | 236 | 237 | DAT 238 | 239 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 240 | ' Data 241 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 242 | 243 | invisibleScale long (12 << 12) + 256 ' Scaling for inactive video. 244 | visibleScale long (4 << 12) + 16 ' Scaling for active video. 245 | blankPixels long 1024 ' Blank scanline pixel length. 246 | syncPixels long $0F_FF_FF_F0 ' F-porch, h-sync, and b-porch. 247 | HSyncColors long $01_03_01_03 ' Horizontal sync color mask. 248 | VSyncColors long $00_02_00_02 ' Vertical sync color mask. 249 | HVSyncColors long $03_03_03_03 ' Horizontal and vertical sync colors. 250 | 251 | FPorchStatus long %001 << 16 + 240 252 | VSyncStatus long %011 << 16 253 | BPorchStatus long %101 << 16 254 | 255 | ' //////////////////////Configuration Settings///////////////////////////////////////////////////////////////////////////////// 256 | 257 | directionState long 0 258 | videoState long 0 259 | frequencyState long 0 260 | 261 | ' //////////////////////Addresses////////////////////////////////////////////////////////////////////////////////////////////// 262 | 263 | syncIndicatorAddress long 0 264 | 265 | ' //////////////////////Run Time Variables///////////////////////////////////////////////////////////////////////////////////// 266 | 267 | counter res 1 268 | buffer res 1 269 | 270 | tileCounter res 1 271 | tilesCounter res 1 272 | 273 | displayCounter res 1 274 | 275 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 276 | 277 | fit 496 278 | 279 | DAT 280 | 281 | ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 282 | 283 | {{ 284 | 285 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 286 | // TERMS OF USE: MIT License 287 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 288 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 289 | // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 290 | // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 291 | // Software is furnished to do so, subject to the following conditions: 292 | // 293 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 294 | // Software. 295 | // 296 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 297 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 298 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 299 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 300 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 301 | }} 302 | -------------------------------------------------------------------------------- /src/lib_vjet/graphtest.spin: -------------------------------------------------------------------------------- 1 | CON 2 | 3 | _clkmode = XTAL1 + PLL16X 4 | _xinfreq = 7_372_800 5 | 6 | DLIST_SIZE = 500 7 | 8 | WIDTH = 256 9 | HEIGHT = 240 10 | 11 | OBJ 12 | vga: "VJET_vUXM_vga.spin" 13 | render: "VJET_vUXM_rendering.spin" 14 | gl: "VJET_v01_displaylist.spin" 15 | font : "hexfont.spin" 16 | 17 | 18 | VAR 19 | 20 | long framecount,vga_status,dlist_ptr 21 | long dlist1[DLIST_SIZE],dlist2[DLIST_SIZE] 22 | long linebuffers[(256*8)/4] 23 | 24 | 25 | PUB main | i,j,x,j2 26 | 27 | vga.start(16/8,@linebuffers,@vga_status) 28 | 29 | 30 | 31 | dlist_ptr:=$8080 32 | x:=false 33 | render.start(0,3,@linebuffers,@dlist_ptr,@vga_status,@x) 34 | render.start(1,3,@linebuffers,@dlist_ptr,@vga_status,@x) 35 | render.start(2,3,@linebuffers,@dlist_ptr,@vga_status,@x) 36 | x:=true 37 | 38 | repeat 39 | Vblank 40 | if framecount&1 41 | dlist_ptr:=@dlist1 42 | gl.start(@dlist2,constant(DLIST_SIZE*4)) 43 | else 44 | dlist_ptr:=@dlist2 45 | gl.start(@dlist1,constant(DLIST_SIZE*4)) 46 | 47 | \draw 48 | gl.done 49 | framecount++ 50 | 51 | 52 | PRI draw | i,j,cx,cy,cx2,cy2,col 53 | 54 | gl.set_clip(0,HEIGHT<<16,0,WIDTH<<16) 55 | 56 | repeat i from 0 to 4 57 | repeat j from 0 to 4 58 | if (i^j)&1 59 | col:= $5555 60 | else 61 | col:= $AAAA 62 | gl.box(cx:=08+i*40,cy:=20+j*40,cx+40,cy+40,col) 63 | 64 | repeat i from @stockdata to @stockdata_end-16 step 8 65 | cx := (10+long[i][0]*5)<<16 66 | cy := (220-long[i][1]/200)<<16 67 | cx2 := (10+long[i][2]*5)<<16 68 | cy2 := (220-long[i][3]/200)<<16 69 | 'gl.point(28+cx,215-cy,$C0C0) 70 | gl.line(cx,cy,cx2,cy2,$C0C0) 71 | 72 | repeat i from @stockdata to @stockdata_end-8 step 8 73 | cx := (10+long[i][0]*5)<<16 74 | cy := (220-long[i][1]/200)<<16 75 | gl.point(cx~>16,cy~>16,$FFFF) 76 | 77 | gl.text(20,10,0,0,string("STOCK PRICE HISTORY"),font.get,$FFFF) 78 | gl.text(207,17,0,0,string("-400"),font.get,$FFFF) 79 | gl.text(207,215,0,0,string("- 0"),font.get,$FFFF) 80 | gl.text(5,225,0,0,string("JAN 21"),font.get,$FFFF) 81 | gl.text(190,225,0,0,string("MAR 02"),font.get,$FFFF) 82 | 83 | PUB Vblank 84 | 85 | repeat while vga_status&$01_00_00 86 | repeat until vga_status&$01_00_00 87 | 88 | DAT 89 | 90 | stockdata 91 | long 0,round(43.029999*100.0) 92 | long 1,round(65.010002*100.0) 93 | long 4,round(76.790001*100.0) 94 | long 5,round(147.979996*100.0) 95 | long 6,round(347.510010*100.0) 96 | long 7,round(193.600006*100.0) 97 | long 8,round(325.000000*100.0) 98 | long 11,round(225.000000*100.0) 99 | long 12,round(90.000000*100.0) 100 | long 13,round(92.410004*100.0) 101 | long 14,round(53.500000*100.0) 102 | long 15,round(63.770000*100.0) 103 | long 18,round(60.000000*100.0) 104 | long 19,round(50.310001*100.0) 105 | long 20,round(51.200001*100.0) 106 | long 21,round(51.099998*100.0) 107 | long 22,round(52.400002*100.0) 108 | long 26,round(49.509998*100.0) 109 | long 27,round(45.939999*100.0) 110 | long 28,round(40.689999*100.0) 111 | long 29,round(40.590000*100.0) 112 | long 32,round(46.000000*100.0) 113 | long 33,round(44.970001*100.0) 114 | long 34,round(91.709999*100.0) 115 | long 35,round(108.730003*100.0) 116 | long 36,round(101.739998*100.0) 117 | long 39,round(120.400002*100.0) 118 | stockdata_end 119 | -------------------------------------------------------------------------------- /src/lib_vjet/hexfont.spin: -------------------------------------------------------------------------------- 1 | VAR 2 | 3 | long init 4 | 5 | 6 | PUB get | i,l 7 | 8 | ifnot init~~ 9 | 'wtf_fastspin '' call another function to make this a non-leaf function to get fastspin to not allocate a million registers 10 | repeat i from 0 to constant((@fontptrs_last - @fontptrs)/2) 11 | ifnot fontptrs[i] >> 15 12 | fontptrs[i] := @@fontptrs[i] 13 | 14 | return @fontptrs 15 | 16 | 17 | DAT 18 | 19 | {{ 20 | Terrible 8x8 version of "Bump IT UP" by Aaron Amar 21 | https://fontstruct.com/fontstructions/show/155156/bump_it_up 22 | 23 | Licensed as Creative Commons Attribution Share Alike 24 | 25 | }} 26 | 27 | fontptrs word 28 | word $8080 ' space 29 | word (@chr_exclamation) 30 | word (@chr_minus)[11] ' skip gunk 31 | word (@chr_minus) 32 | word (@chr_dot) 33 | word (@chr_minus)[1] ' skip / 34 | word (@chr_o) ' use O as 0 35 | word (@chr_1) 36 | word (@chr_2) 37 | word (@chr_3) 38 | word (@chr_4) 39 | word (@chr_5) 40 | word (@chr_6) 41 | word (@chr_7) 42 | word (@chr_8) 43 | word (@chr_9) 44 | word (@chr_colon) 45 | word (@chr_minus)[6] ' skip gunk 46 | word (@chr_a) 47 | word (@chr_b) 48 | word (@chr_c) 49 | word (@chr_d) 50 | word (@chr_e) 51 | word (@chr_f) 52 | word (@chr_g) 53 | word (@chr_h) 54 | word (@chr_i) 55 | word (@chr_j) 56 | word (@chr_k) 57 | word (@chr_l) 58 | word (@chr_m) 59 | word (@chr_n) 60 | word (@chr_o) 61 | word (@chr_p) 62 | word (@chr_q) 63 | word (@chr_r) 64 | word (@chr_s) 65 | word (@chr_t) 66 | word (@chr_u) 67 | word (@chr_v) 68 | word (@chr_w) 69 | word (@chr_x) 70 | word (@chr_y) 71 | fontptrs_last 72 | word (@chr_z) 73 | 74 | 75 | DAT 76 | 77 | ' import char 0 78 | chr_exclamation 79 | byte %00000110 80 | byte %00000110 81 | byte %00000110 82 | byte %00000110 83 | byte %00000110 84 | byte %00000000 85 | byte %00000110 86 | byte %00000110 87 | 88 | ' import char 1 89 | chr_minus 90 | byte %00000000 91 | byte %00000000 92 | byte %00000000 93 | byte %01111110 94 | byte %01111110 95 | byte %00000000 96 | byte %00000000 97 | byte %00000000 98 | ' import char 2 99 | chr_dot 100 | byte %00000000 101 | byte %00000000 102 | byte %00000000 103 | byte %00000000 104 | byte %00000000 105 | byte %00000000 106 | byte %00000110 107 | byte %00000110 108 | { 109 | ' import char 3 110 | chr_0 111 | byte %11111110 112 | byte %11111111 113 | byte %11000011 114 | byte %11011011 115 | byte %11011011 116 | byte %11000011 117 | byte %11111111 118 | byte %01111111 119 | } 120 | ' import char 4 121 | chr_1 122 | byte %00001111 123 | byte %00011111 124 | byte %00011000 125 | byte %00011000 126 | byte %00011000 127 | byte %00011000 128 | byte %11111111 129 | byte %11111111 130 | ' import char 5 131 | chr_2 132 | byte %11111111 133 | byte %11111111 134 | byte %11000000 135 | byte %11111110 136 | byte %01111111 137 | byte %00000011 138 | byte %11111111 139 | byte %11111111 140 | ' import char 6 141 | chr_3 142 | byte %01111111 143 | byte %11111111 144 | byte %11000000 145 | byte %11111111 146 | byte %11111111 147 | byte %11000000 148 | byte %11111111 149 | byte %01111111 150 | ' import char 7 151 | chr_4 152 | byte %11000011 153 | byte %11000011 154 | byte %11000011 155 | byte %11000011 156 | byte %11111111 157 | byte %11111110 158 | byte %11000000 159 | byte %11000000 160 | ' import char 8 161 | chr_5 162 | byte %11111111 163 | byte %11111111 164 | byte %00000011 165 | byte %01111111 166 | byte %11111110 167 | byte %11000000 168 | byte %11111111 169 | byte %11111111 170 | ' import char 9 171 | chr_6 172 | byte %11111111 173 | byte %11111111 174 | byte %00000011 175 | byte %01111111 176 | byte %11111111 177 | byte %11000011 178 | byte %11111111 179 | byte %11111111 180 | ' import char 10 181 | chr_7 182 | byte %01111111 183 | byte %11111111 184 | byte %11000000 185 | byte %11000000 186 | byte %11000000 187 | byte %11000000 188 | byte %11000000 189 | byte %11000000 190 | ' import char 11 191 | chr_8 192 | byte %11111110 193 | byte %11111111 194 | byte %11000011 195 | byte %11111111 196 | byte %11111111 197 | byte %11000011 198 | byte %11111111 199 | byte %01111111 200 | ' import char 12 201 | chr_9 202 | byte %11111111 203 | byte %11111111 204 | byte %11000011 205 | byte %11111111 206 | byte %11111110 207 | byte %11000000 208 | byte %11111111 209 | byte %11111111 210 | ' import char 13 211 | chr_colon 212 | byte %00000000 213 | byte %00000000 214 | byte %00000000 215 | byte %00010000 216 | byte %00011000 217 | byte %00000000 218 | byte %00011000 219 | byte %00001000 220 | ' import char 14 221 | chr_a 222 | byte %11111110 223 | byte %11111111 224 | byte %11000011 225 | byte %11000011 226 | byte %11111111 227 | byte %11111111 228 | byte %11000011 229 | byte %11000011 230 | ' import char 15 231 | chr_b 232 | byte %11111111 233 | byte %11111111 234 | byte %11000011 235 | byte %01111111 236 | byte %01111111 237 | byte %11000011 238 | byte %11111111 239 | byte %11111111 240 | ' import char 16 241 | chr_c 242 | byte %11111111 243 | byte %11111111 244 | byte %00000011 245 | byte %00000011 246 | byte %00000011 247 | byte %00000011 248 | byte %11111111 249 | byte %11111110 250 | ' import char 17 251 | chr_d 252 | byte %01111111 253 | byte %11111111 254 | byte %11000011 255 | byte %11000011 256 | byte %11000011 257 | byte %11000011 258 | byte %11111111 259 | byte %11111111 260 | ' import char 18 261 | chr_e 262 | byte %11111111 263 | byte %11111111 264 | byte %00000011 265 | byte %11111111 266 | byte %11111111 267 | byte %00000011 268 | byte %11111111 269 | byte %11111110 270 | ' import char 19 271 | chr_f 272 | byte %11111110 273 | byte %11111111 274 | byte %00000011 275 | byte %11111111 276 | byte %11111111 277 | byte %00000011 278 | byte %00000011 279 | byte %00000011 280 | ' import char 20 281 | chr_g 282 | byte %11111111 283 | byte %11111111 284 | byte %00000011 285 | byte %11000011 286 | byte %11000011 287 | byte %11000011 288 | byte %11111111 289 | byte %01111111 290 | ' import char 21 291 | chr_h 292 | byte %11000011 293 | byte %11000011 294 | byte %11000011 295 | byte %11111111 296 | byte %11111111 297 | byte %11000011 298 | byte %11000011 299 | byte %11000011 300 | ' import char 22 301 | chr_i 302 | byte %11111111 303 | byte %11111111 304 | byte %00011000 305 | byte %00011000 306 | byte %00011000 307 | byte %00011000 308 | byte %11111111 309 | byte %11111111 310 | ' import char 23 311 | chr_j 312 | byte %11000000 313 | byte %11000000 314 | byte %11000000 315 | byte %11000000 316 | byte %11000000 317 | byte %11000011 318 | byte %11111111 319 | byte %01111111 320 | ' import char 24 321 | chr_k 322 | byte %11000011 323 | byte %11000011 324 | byte %11000011 325 | byte %01111111 326 | byte %01111111 327 | byte %11000011 328 | byte %11000011 329 | byte %11000011 330 | ' import char 25 331 | chr_l 332 | byte %00000011 333 | byte %00000011 334 | byte %00000011 335 | byte %00000011 336 | byte %00000011 337 | byte %00000011 338 | byte %11111111 339 | byte %11111110 340 | ' import char 26 341 | chr_m 342 | byte %11100111 343 | byte %11111111 344 | byte %11011011 345 | byte %11011011 346 | byte %11011011 347 | byte %11011011 348 | byte %11011011 349 | byte %11011011 350 | ' import char 27 351 | chr_n 352 | byte %01111111 353 | byte %11111111 354 | byte %11000011 355 | byte %11000011 356 | byte %11000011 357 | byte %11000011 358 | byte %11000011 359 | byte %11000011 360 | ' import char 28 361 | chr_o 362 | byte %11111110 363 | byte %11111111 364 | byte %11000011 365 | byte %11000011 366 | byte %11000011 367 | byte %11000011 368 | byte %11111111 369 | byte %01111111 370 | ' import char 29 371 | chr_p 372 | byte %11111111 373 | byte %11111111 374 | byte %11000011 375 | byte %11000011 376 | byte %11111111 377 | byte %01111111 378 | byte %00000011 379 | byte %00000011 380 | ' import char 30 381 | chr_q 382 | byte %11111110 383 | byte %11111111 384 | byte %11000011 385 | byte %11000011 386 | byte %11000011 387 | byte %11011011 388 | byte %11111111 389 | byte %01111111 390 | ' import char 31 391 | chr_r 392 | byte %01111111 393 | byte %11111111 394 | byte %11000011 395 | byte %11000011 396 | byte %01111111 397 | byte %01111111 398 | byte %11000011 399 | byte %11000011 400 | ' import char 32 401 | chr_s 402 | byte %11111110 403 | byte %11111111 404 | byte %00000011 405 | byte %11111111 406 | byte %11111111 407 | byte %11000000 408 | byte %11111111 409 | byte %01111111 410 | ' import char 33 411 | chr_t 412 | byte %11111111 413 | byte %11111111 414 | byte %00011000 415 | byte %00011000 416 | byte %00011000 417 | byte %00011000 418 | byte %00011000 419 | byte %00011000 420 | ' import char 34 421 | chr_u 422 | byte %11000011 423 | byte %11000011 424 | byte %11000011 425 | byte %11000011 426 | byte %11000011 427 | byte %11000011 428 | byte %11111111 429 | byte %11111110 430 | ' import char 35 431 | chr_v 432 | byte %11000011 433 | byte %11000011 434 | byte %11000011 435 | byte %11000011 436 | byte %11000011 437 | byte %11000011 438 | byte %11111111 439 | byte %01111111 440 | ' import char 36 441 | chr_w 442 | byte %11011011 443 | byte %11011011 444 | byte %11011011 445 | byte %11011011 446 | byte %11011011 447 | byte %11011011 448 | byte %11111111 449 | byte %11111110 450 | ' import char 37 451 | chr_x 452 | byte %11000011 453 | byte %11000011 454 | byte %11000011 455 | byte %01111110 456 | byte %01111110 457 | byte %11000011 458 | byte %11000011 459 | byte %11000011 460 | ' import char 38 461 | chr_y 462 | byte %11000011 463 | byte %11000011 464 | byte %11000011 465 | byte %11000011 466 | byte %11111111 467 | byte %01111110 468 | byte %00011000 469 | byte %00011000 470 | ' import char 39 471 | chr_z 472 | byte %01111111 473 | byte %11111111 474 | byte %11000000 475 | byte %11111111 476 | byte %11111111 477 | byte %00000011 478 | byte %11111111 479 | byte %11111110 480 | { 481 | ' import char 40 482 | byte %00000000 483 | byte %00000000 484 | byte %00000000 485 | byte %00000000 486 | byte %00000000 487 | byte %00000000 488 | byte %00000000 489 | byte %00000000 490 | } -------------------------------------------------------------------------------- /src/lib_vjet/vjet_test.spin: -------------------------------------------------------------------------------- 1 | CON 2 | 3 | _clkmode = XTAL1 + PLL16X 4 | _xinfreq = 7_372_800 5 | 6 | DLIST_SIZE = 900 7 | 8 | WIDTH = render#WIDTH 9 | HEIGHT = render#NUM_LINES 10 | 11 | 12 | OBJ 13 | vga: "VJET_vUXM_vga.spin" 14 | render: "VJET_vUXM_rendering.spin" 15 | gl: "VJET_v01_displaylist.spin" 16 | font : "hexfont.spin" 17 | 18 | 19 | VAR 20 | 21 | long framecount,vga_status,dlist_ptr 22 | long dlist1[DLIST_SIZE],dlist2[DLIST_SIZE] 23 | long linebuffers[(WIDTH*8)/4] 24 | 25 | PUB main | i,j,x,j2 26 | 27 | vga.start(16/8,@linebuffers,@vga_status) 28 | 29 | 30 | 31 | dlist_ptr:=$8080 32 | x:=false 33 | render.start(0,3,@linebuffers,@dlist_ptr,@vga_status,@x) 34 | render.start(1,3,@linebuffers,@dlist_ptr,@vga_status,@x) 35 | render.start(2,3,@linebuffers,@dlist_ptr,@vga_status,@x) 36 | x:=true 37 | 38 | repeat 39 | Vblank 40 | if framecount&1 41 | dlist_ptr:=@dlist1 42 | gl.start(@dlist2,constant(DLIST_SIZE*4)) 43 | else 44 | dlist_ptr:=@dlist2 45 | gl.start(@dlist1,constant(DLIST_SIZE*4)) 46 | 47 | \draw 48 | gl.done 49 | framecount++ 50 | 51 | 52 | PRI draw | cx,cy 53 | 54 | gl.set_clip(0,HEIGHT<<16,0,WIDTH<<16) 55 | 56 | gl.triangle(constant((WIDTH/2)<<16),constant(-HEIGHT<<16),constant(-WIDTH<<16),constant(HEIGHT<<16),constant(2*WIDTH<<16),constant(HEIGHT<<16),$ECEC) 57 | 58 | gl.triangle(208<<16 + sin(0000+framecount<<5)*75,90<<16 + sin(2048+framecount<<5)*75,{ 59 | }208<<16 + sin(2730+framecount<<5)*75,90<<16 + sin(4778+framecount<<5)*75,{ 60 | }208<<16 + sin(5460+framecount<<5)*75,90<<16 + sin(7508+framecount<<5)*75, $0055) 61 | 62 | gl.triangle(192<<16 + sin(0000+framecount<<5)*80,90<<16 + sin(2048+framecount<<5)*80,{ 63 | }192<<16 + sin(2730+framecount<<5)*80,90<<16 + sin(4778+framecount<<5)*80,{ 64 | }192<<16 + sin(5460+framecount<<5)*80,90<<16 + sin(7508+framecount<<5)*80, $5555) 65 | 66 | gl.triangle(176<<16 + sin(0000+framecount<<5)*85,90<<16 + sin(2048+framecount<<5)*85,{ 67 | }176<<16 + sin(2730+framecount<<5)*85,90<<16 + sin(4778+framecount<<5)*85,{ 68 | }176<<16 + sin(5460+framecount<<5)*85,90<<16 + sin(7508+framecount<<5)*85, $55AA) 69 | 70 | gl.triangle(160<<16 + sin(0000+framecount<<5)*90,90<<16 + sin(2048+framecount<<5)*90,{ 71 | }160<<16 + sin(2730+framecount<<5)*90,90<<16 + sin(4778+framecount<<5)*90,{ 72 | }160<<16 + sin(5460+framecount<<5)*90,90<<16 + sin(7508+framecount<<5)*90, $AAAA) 73 | 74 | 75 | gl.triangle(128<<16 + sin(0000-framecount<<4)*500,90<<16 + sin(2048-framecount<<4)*500,{ 76 | }128<<16 + sin(0100-framecount<<4)*500,90<<16 + sin(2148-framecount<<4)*500,{ 77 | }128<<16 ,90<<16 , $C0C0) 78 | gl.triangle(128<<16 + sin(0100-framecount<<4)*500,90<<16 + sin(2148-framecount<<4)*500,{ 79 | }128<<16 + sin(0200-framecount<<4)*500,90<<16 + sin(2248-framecount<<4)*500,{ 80 | }128<<16 ,90<<16 , $D0D0) 81 | gl.triangle(128<<16 + sin(0200-framecount<<4)*500,90<<16 + sin(2248-framecount<<4)*500,{ 82 | }128<<16 + sin(0300-framecount<<4)*500,90<<16 + sin(2348-framecount<<4)*500,{ 83 | }128<<16 ,90<<16 , $F0F0) 84 | gl.triangle(128<<16 + sin(0300-framecount<<4)*500,90<<16 + sin(2348-framecount<<4)*500,{ 85 | }128<<16 + sin(0400-framecount<<4)*500,90<<16 + sin(2448-framecount<<4)*500,{ 86 | }128<<16 ,90<<16 , $7474) 87 | gl.triangle(128<<16 + sin(0400-framecount<<4)*500,90<<16 + sin(2448-framecount<<4)*500,{ 88 | }128<<16 + sin(0500-framecount<<4)*500,90<<16 + sin(2548-framecount<<4)*500,{ 89 | }128<<16 ,90<<16 , $3C3C) 90 | gl.triangle(128<<16 + sin(0500-framecount<<4)*500,90<<16 + sin(2548-framecount<<4)*500,{ 91 | }128<<16 + sin(0600-framecount<<4)*500,90<<16 + sin(2648-framecount<<4)*500,{ 92 | }128<<16 ,90<<16 , $4848) 93 | 94 | 95 | gl.triangle(144<<16 + sin(0000+framecount<<5)*95,90<<16 + sin(2048+framecount<<5)*95,{ 96 | }144<<16 + sin(2730+framecount<<5)*95,90<<16 + sin(4778+framecount<<5)*95,{ 97 | }144<<16 + sin(5460+framecount<<5)*95,90<<16 + sin(7508+framecount<<5)*95, $AAFF) 98 | 99 | gl.triangle(128<<16 + sin(0000+framecount<<5)*100,90<<16 + sin(2048+framecount<<5)*100,{ 100 | }128<<16 + sin(2730+framecount<<5)*100,90<<16 + sin(4778+framecount<<5)*100,{ 101 | }128<<16 + sin(5460+framecount<<5)*100,90<<16 + sin(7508+framecount<<5)*100, $FFFF) 102 | 103 | gl.text_centered(WIDTH>>1,192 + sin(0000+framecount<<6)~>12,0,2,string(" WOOO! SPINNING TRIANGLES!"),font.get,$FFFF) 104 | 105 | PUB sin(angle) : s | c,z 106 | 'angle: 0..8192 = 360deg 107 | s := angle 108 | if angle & $800 109 | s := -s 110 | s |= $E000>>1 111 | s <<= 1 112 | s := word[s] 113 | if angle & $1000 114 | s := -s ' return sin = -$FFFF..+$FFFF 115 | 116 | PUB Vblank 117 | 118 | repeat while vga_status&$01_00_00 119 | repeat until vga_status&$01_00_00 120 | -------------------------------------------------------------------------------- /src/terminal_ftdi.spin: -------------------------------------------------------------------------------- 1 | {{ 2 | File: Parallax Serial Terminal.spin 3 | Version: 1.0 4 | Copyright (c) 2009 Parallax, Inc. 5 | See end of file for terms of use. 6 | 7 | Authors: Jeff Martin, Andy Lindsay, Chip Gracey 8 | }} 9 | 10 | { 11 | HISTORY: 12 | This object is made for direct use with the Parallax Serial Terminal; a simple serial communication program 13 | available with the Propeller Tool installer and also separately via the Parallax website (www.parallax.com). 14 | 15 | This object is heavily based on FullDuplexSerialPlus (by Andy Lindsay), which is itself heavily based on 16 | FullDuplexSerial (by Chip Gracey). 17 | 18 | USAGE: 19 | Call start, or startRxTx, first. 20 | 21 | } 22 | 23 | CON 24 | 25 | BUFFER_LENGTH = 512 'Recommended as 64 or higher, but can be 2, 4, 8, 16, 32, 64, 128, 256 or 512. 26 | BUFFER_MASK = BUFFER_LENGTH - 1 27 | BUFFER_FULLISH = BUFFER_LENGTH / 2 28 | BUFFER_EMPTYISH = BUFFER_LENGTH / 8 29 | 30 | MAXSTR_LENGTH = 255 'Maximum length of received numerical string (not including zero terminator). 31 | 32 | XOFF = 19 ' XOFF 33 | XON = 17 ' XON 34 | NL = 13 ' NL: New Line 35 | LF = 10 ' LF: Line Feed 36 | 37 | 38 | VAR 39 | 40 | long cog 'Cog flag/id 41 | 42 | long status_xoff 'Status of XOFF in XON/XOFF transmission 43 | 44 | long rx_head '9 contiguous longs (must keep order) 45 | long rx_tail 46 | long tx_head 47 | long tx_tail 48 | long rx_pin 49 | long tx_pin 50 | long rxtx_mode 51 | long bit_ticks 52 | long buffer_ptr 53 | 54 | byte rx_buffer[BUFFER_LENGTH] 'Receive and transmit buffers 55 | byte tx_buffer[BUFFER_LENGTH] 56 | 57 | byte str_buffer[MAXSTR_LENGTH+1] 'String buffer for numerical strings 58 | 59 | 60 | PUB start(baudrate) : okay 61 | {{Start communication with the Parallax Serial Terminal using the Propeller's programming connection. 62 | Waits 1/4 second for connection, then clears screen. 63 | Parameters: 64 | baudrate - bits per second. Make sure it matches the Parallax Serial Terminal's 65 | Baud Rate field. 66 | Returns : True (non-zero) if cog started, or False (0) if no cog is available.}} 67 | 68 | okay := startRxTx(31, 30, 0, baudrate) 69 | waitcnt(clkfreq >> 2 + cnt) 'Wait 1/4 second for PST 70 | 71 | 72 | PUB startRxTx(rxpin, txpin, mode, baudrate) : okay 73 | {{Start serial communication with designated pins, mode, and baud. 74 | Parameters: 75 | rxpin - input pin; receives signals from external device's TX pin. 76 | txpin - output pin; sends signals to external device's RX pin. 77 | mode - signaling mode (4-bit pattern). 78 | bit 0 - inverts rx. 79 | bit 1 - inverts tx. 80 | bit 2 - open drain/source tx. 81 | bit 3 - ignore tx echo on rx. 82 | baudrate - bits per second. 83 | Returns : True (non-zero) if cog started, or False (0) if no cog is available.}} 84 | 85 | stop 86 | longfill(@rx_head, 0, 4) 87 | longmove(@rx_pin, @rxpin, 3) 88 | bit_ticks := clkfreq / baudrate 89 | buffer_ptr := @rx_buffer 90 | status_xoff := FALSE 91 | okay := cog := cognew(@entry, @rx_head) + 1 92 | 93 | 94 | PUB stop 95 | {{Stop serial communication; frees a cog.}} 96 | 97 | if cog 98 | cogstop(cog~ - 1) 99 | longfill(@rx_head, 0, 9) 100 | 101 | 102 | PUB tx(bytechr) 103 | {{Send single-byte character. Waits for room in transmit buffer if necessary. 104 | Parameter: 105 | bytechr - character (ASCII byte value) to send.}} 106 | 107 | repeat until (tx_tail <> ((tx_head + 1) & BUFFER_MASK)) 108 | 109 | tx_buffer[tx_head] := bytechr 110 | tx_head := ++tx_head & BUFFER_MASK 111 | 112 | if rxtx_mode & %1000 113 | rx 114 | 115 | 116 | PUB txn(bytechr, count) 117 | {{Send multiple copies of a single-byte character. Waits for room in transmit buffer if necessary. 118 | Parameters: 119 | bytechr - character (ASCII byte value) to send. 120 | count - number of bytechrs to send.}} 121 | 122 | repeat count 123 | tx(bytechr) 124 | 125 | 126 | PUB txCheck : truefalse 127 | {{Check and return true if space in transmit buffer; return immediately. 128 | Returns: t|f}} 129 | 130 | truefalse := tx_tail <> ((tx_head + 1) & BUFFER_MASK ) 131 | 132 | 133 | PUB rx : rxbyte 134 | {{Receive single-byte character. Waits until character received. 135 | Returns: $00..$FF}} 136 | 137 | repeat until rxCount > 0 138 | 139 | rxbyte := rx_buffer[rx_tail] 140 | rx_tail := ++rx_tail & BUFFER_MASK 141 | 142 | 143 | PUB rxCount : count 144 | {{Get count of characters in receive buffer. Manages XON/XOFF flow control. 145 | Returns: number of characters waiting in receive buffer.}} 146 | 147 | count := rx_head - rx_tail 148 | count -= BUFFER_LENGTH * (count < 0) 149 | 150 | if count =< BUFFER_EMPTYISH and status_xoff == TRUE 151 | status_xoff := FALSE 152 | tx(XON) 153 | 154 | elseif count => BUFFER_FULLISH and status_xoff == FALSE 155 | status_xoff := TRUE 156 | tx(XOFF) 157 | 158 | 159 | PUB rxFlush 160 | {{Flush receive buffer.}} 161 | 162 | rx_tail := rx_head := 0 163 | 164 | 165 | PUB rxCheck : truefalse 166 | {Check if character received; return immediately. 167 | Returns: t|f} 168 | 169 | truefalse := rx_tail <> rx_head 170 | 171 | 172 | CON 173 | 174 | ' Terminal Control 175 | 176 | 177 | PUB clear 178 | {{Clear screen and place cursor at top-left.}} 179 | 180 | str(string(27,"[2J")) 181 | 182 | 183 | PUB clearEnd 184 | {{Clear line from cursor to end of line.}} 185 | 186 | str(string(27,"[0K")) 187 | 188 | PUB clearBelow 189 | {{Clear all lines below cursor.}} 190 | 191 | str(string(27,"[J")) 192 | 193 | 194 | PUB home 195 | {{Send cursor to home position (top-left).}} 196 | 197 | str(string(27,"[H")) 198 | 199 | 200 | PUB position(x, y) 201 | {{Position cursor at column x, row y (from top-left).}} 202 | str(string(27,"[")) ' Position Cursor 203 | dec(y) 204 | tx(";") 205 | dec(x) 206 | tx("H") 207 | 208 | 209 | PUB saveCurPos 210 | str(string(27,"7")) 211 | 212 | 213 | PUB restoreCurPos 214 | str(string(27,"8")) 215 | 216 | 217 | PUB hideCursor 218 | 219 | str(string(27,"[?25l")) ' Hide Cursor 220 | 221 | 222 | PUB showCursor 223 | str(string(27,"[?25h")) ' Show Cursor 224 | 225 | 226 | PUB newLine 227 | {{Send cursor to new line (carriage return plus line feed).}} 228 | 229 | tx(NL) 230 | tx(LF) 231 | 232 | 233 | PUB lineFeed 234 | {{Send cursor down to next line.}} 235 | 236 | tx(LF) 237 | 238 | 239 | CON 240 | 241 | ' String Handling 242 | 243 | 244 | PUB str(stringptr) 245 | {{Send zero terminated string. 246 | Parameter: 247 | stringptr - pointer to zero terminated string to send.}} 248 | 249 | repeat strsize(stringptr) 250 | tx(byte[stringptr++]) 251 | 252 | 253 | PUB strIn(stringptr) 254 | {{Receive a string (carriage return terminated) and stores it (zero terminated) starting at stringptr. 255 | Waits until full string received. 256 | Parameter: 257 | stringptr - pointer to memory in which to store received string characters. 258 | Memory reserved must be large enough for all string characters plus a zero terminator.}} 259 | 260 | strInMax(stringptr, -1) 261 | 262 | 263 | PUB strInMax(stringptr, maxcount) 264 | {{Receive a string of characters (either carriage return terminated or maxcount in length) and stores it (zero terminated) 265 | starting at stringptr. Waits until either full string received or maxcount characters received. 266 | Parameters: 267 | stringptr - pointer to memory in which to store received string characters. 268 | Memory reserved must be large enough for all string characters plus a zero terminator (maxcount + 1). 269 | maxcount - maximum length of string to receive, or -1 for unlimited.}} 270 | 271 | repeat while (maxcount--) 'While maxcount not reached 272 | if (byte[stringptr++] := rx) == NL 'Get chars until NL 273 | quit 274 | byte[stringptr+(byte[stringptr-1] == NL)]~ 'Zero terminate string; overwrite NL or append 0 char 275 | 276 | 277 | 278 | CON 279 | 280 | ' Numeric and Alternate Base Handling 281 | 282 | 283 | PUB dec(value) | i, x 284 | {{Send value as decimal characters. 285 | Parameter: 286 | value - byte, word, or long value to send as decimal characters.}} 287 | 288 | x := value == NEGX 'Check for max negative 289 | if value < 0 290 | value := ||(value+x) 'If negative, make positive; adjust for max negative 291 | tx("-") 'and output sign 292 | 293 | i := 1_000_000_000 'Initialize divisor 294 | 295 | repeat 10 'Loop for 10 digits 296 | if value => i 297 | tx(value / i + "0" + x*(i == 1)) 'If non-zero digit, output digit; adjust for max negative 298 | value //= i 'and digit from value 299 | result~~ 'flag non-zero found 300 | elseif result or i == 1 301 | tx("0") 'If zero digit (or only digit) output it 302 | i /= 10 'Update divisor 303 | 304 | 305 | PUB decIn : value 306 | {{Receive carriage return terminated string of characters representing a decimal value. 307 | Returns: the corresponding decimal value.}} 308 | 309 | strInMax(@str_buffer, MAXSTR_LENGTH) 310 | value := strToBase(@str_buffer, 10) 311 | 312 | 313 | PUB bin(value, digits) 314 | {{Send value as binary characters up to digits in length. 315 | Parameters: 316 | value - byte, word, or long value to send as binary characters. 317 | digits - number of binary digits to send. Will be zero padded if necessary.}} 318 | 319 | value <<= 32 - digits 320 | repeat digits 321 | tx((value <-= 1) & 1 + "0") 322 | 323 | 324 | PUB binIn : value 325 | {{Receive carriage return terminated string of characters representing a binary value. 326 | Returns: the corresponding binary value.}} 327 | 328 | strInMax(@str_buffer, MAXSTR_LENGTH) 329 | value := strToBase(@str_buffer, 2) 330 | 331 | 332 | PUB hex(value, digits) 333 | {{Send value as hexadecimal characters up to digits in length. 334 | Parameters: 335 | value - byte, word, or long value to send as hexadecimal characters. 336 | digits - number of hexadecimal digits to send. Will be zero padded if necessary.}} 337 | 338 | value <<= (8 - digits) << 2 339 | repeat digits 340 | tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F")) 341 | 342 | 343 | PUB hexIn : value 344 | {{Receive carriage return terminated string of characters representing a hexadecimal value. 345 | Returns: the corresponding hexadecimal value.}} 346 | 347 | strInMax(@str_buffer, MAXSTR_LENGTH) 348 | value := strToBase(@str_buffer, 16) 349 | 350 | 351 | PRI strToBase(stringptr, base) : value | chr, index 352 | {Converts a zero terminated string representation of a number to a value in the designated base. 353 | Ignores all non-digit characters (except negative (-) when base is decimal (10)).} 354 | 355 | value := index := 0 356 | repeat until ((chr := byte[stringptr][index++]) == 0) 357 | chr := -15 + --chr & %11011111 + 39*(chr > 56) 'Make "0"-"9","A"-"F","a"-"f" be 0 - 15, others out of range 358 | if (chr > -1) and (chr < base) 'Accumulate valid values into result; ignore others 359 | value := value * base + chr 360 | if (base == 10) and (byte[stringptr] == "-") 'If decimal, address negative sign; ignore otherwise 361 | value := - value 362 | 363 | 364 | DAT 365 | 366 | '*********************************** 367 | '* Assembly language serial driver * 368 | '*********************************** 369 | 370 | org 371 | ' 372 | ' 373 | ' Entry 374 | ' 375 | entry mov t1,par 'get structure address 376 | add t1,#4 << 2 'skip past heads and tails 377 | 378 | rdlong t2,t1 'get rx_pin 379 | mov rxmask,#1 380 | shl rxmask,t2 381 | 382 | add t1,#4 'get tx_pin 383 | rdlong t2,t1 384 | mov txmask,#1 385 | shl txmask,t2 386 | 387 | add t1,#4 'get rxtx_mode 388 | rdlong rxtxmode,t1 389 | 390 | add t1,#4 'get bit_ticks 391 | rdlong bitticks,t1 392 | 393 | add t1,#4 'get buffer_ptr 394 | rdlong rxbuff,t1 395 | mov txbuff,rxbuff 396 | add txbuff,#BUFFER_MASK ' transmit buffer address BUFFER_LENGTH 397 | add txbuff,#1 ' BUFFER_LENGTH := BUFFER_MASK + 1 398 | 399 | test rxtxmode,#%100 wz 'init tx pin according to mode 400 | test rxtxmode,#%010 wc 401 | if_z_ne_c or outa,txmask 402 | if_z or dira,txmask 403 | 404 | mov txcode,#transmit 'initialize ping-pong multitasking 405 | ' 406 | ' 407 | ' Receive 408 | ' 409 | receive jmpret rxcode,txcode 'run a chunk of transmit code, then return 410 | 411 | test rxtxmode,#%001 wz 'wait for start bit on rx pin 412 | test rxmask,ina wc 413 | if_z_eq_c jmp #receive 414 | 415 | mov rxbits,#9 'ready to receive byte 416 | mov rxcnt,bitticks 417 | shr rxcnt,#1 418 | add rxcnt,cnt 419 | 420 | :bit add rxcnt,bitticks 'ready next bit period 421 | 422 | :wait jmpret rxcode,txcode 'run a chuck of transmit code, then return 423 | 424 | mov t1,rxcnt 'check if bit receive period done 425 | sub t1,cnt 426 | cmps t1,#0 wc 427 | if_nc jmp #:wait 428 | 429 | test rxmask,ina wc 'receive bit on rx pin 430 | rcr rxdata,#1 431 | djnz rxbits,#:bit 432 | 433 | shr rxdata,#32-9 'justify and trim received byte 434 | and rxdata,#$FF 435 | test rxtxmode,#%001 wz 'if rx inverted, invert byte 436 | if_nz xor rxdata,#$FF 437 | 438 | rdlong t2,par 'save received byte and inc head 439 | add t2,rxbuff 440 | wrbyte rxdata,t2 441 | sub t2,rxbuff 442 | add t2,#1 443 | and t2,#BUFFER_MASK 444 | wrlong t2,par 445 | 446 | jmp #receive 'byte done, receive next byte 447 | ' 448 | ' 449 | ' Transmit 450 | ' 451 | transmit jmpret txcode,rxcode 'run a chunk of receive code, then return 452 | 453 | mov t1,par 'check for head <> tail 454 | add t1,#2 << 2 455 | rdlong t2,t1 456 | add t1,#1 << 2 457 | rdlong t3,t1 458 | cmp t2,t3 wz 459 | if_z jmp #transmit 460 | 461 | add t3,txbuff 'get byte and inc tail 462 | rdbyte txdata,t3 463 | sub t3,txbuff 464 | add t3,#1 465 | and t3,#BUFFER_MASK 466 | wrlong t3,t1 467 | 468 | or txdata,#$100 'ready byte to transmit 469 | shl txdata,#2 470 | or txdata,#1 471 | mov txbits,#11 472 | mov txcnt,cnt 473 | 474 | :bit test rxtxmode,#%100 wz 'output bit on tx pin 475 | test rxtxmode,#%010 wc 'according to mode 476 | if_z_and_c xor txdata,#1 477 | shr txdata,#1 wc 478 | if_z muxc outa,txmask 479 | if_nz muxnc dira,txmask 480 | add txcnt,bitticks 'ready next cnt 481 | 482 | :wait jmpret txcode,rxcode 'run a chunk of receive code, then return 483 | 484 | mov t1,txcnt 'check if bit transmit period done 485 | sub t1,cnt 486 | cmps t1,#0 wc 487 | if_nc jmp #:wait 488 | 489 | djnz txbits,#:bit 'another bit to transmit? 490 | 491 | jmp #transmit 'byte done, transmit next byte 492 | ' 493 | ' 494 | ' Uninitialized data 495 | ' 496 | t1 res 1 497 | t2 res 1 498 | t3 res 1 499 | 500 | rxtxmode res 1 501 | bitticks res 1 502 | 503 | rxmask res 1 504 | rxbuff res 1 505 | rxdata res 1 506 | rxbits res 1 507 | rxcnt res 1 508 | rxcode res 1 509 | 510 | txmask res 1 511 | txbuff res 1 512 | txdata res 1 513 | txbits res 1 514 | txcnt res 1 515 | txcode res 1 516 | 517 | {{ 518 | +------------------------------------------------------------------------------------------------------------------------------+ 519 | | TERMS OF USE: MIT License | 520 | +------------------------------------------------------------------------------------------------------------------------------+ 521 | |Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation | 522 | |files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, | 523 | |modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software| 524 | |is furnished to do so, subject to the following conditions: | 525 | | | 526 | |The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.| 527 | | | 528 | |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 529 | |WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | 530 | |COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 531 | |ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 532 | +------------------------------------------------------------------------------------------------------------------------------+ 533 | }} 534 | -------------------------------------------------------------------------------- /src/ux_module.spin: -------------------------------------------------------------------------------- 1 | ''*************************************** 2 | ''* User Experience Module * 3 | ''* Designed for RC2014 * 4 | ''* Author: Phillip Stevens * 5 | ''* Copyright (c) 2021 * 6 | ''* See end of file for licence * 7 | ''*************************************** 8 | 9 | CON 10 | 11 | _clkmode = XTAL1 + PLL16X 12 | _xinfreq = 7_372_800 13 | 14 | 15 | CON 16 | 17 | ' import some constants from the ACIA Emulation 18 | PORT_ROMWBW = acia#PORT_40 ' Alternate ACIA base port, when used together with SIO/2 Module on 0x80 19 | PORT_DEFAULT = acia#PORT_80 ' Default ACIA base port 20 | PORT_VJET = acia#PORT_C0 21 | 22 | 23 | CON 24 | 25 | ' set these constants based on the Propeller VGA hardware 26 | VGA_BASE_PIN = 16 ' VGA pins 16-23 27 | 28 | ' set these constants based on the Propeller PS/2 hardware 29 | KBD_DATA_PIN = 27 ' KEYBOARD data pin 30 | KBD_CLK_PIN = 26 ' KEYBOARD clock pin 31 | 32 | ' import some constants from the I2C hardware 33 | SDA_PIN = i2c#SDA_PIN ' I2C data pin 34 | SCL_PIN = i2c#SCL_PIN ' I2C clock pin 35 | 36 | ' import some constants from the Propeller Window Manager 37 | VGACOLS = wmf#VGACOLS 38 | VGAROWS = wmf#VGAROWS 39 | 40 | 41 | CON 42 | 43 | ' ASCII control codes 44 | 45 | ASCII_NULL = $00 ' null character 46 | 47 | ASCII_BELL = $07 ' bell 48 | ASCII_BS = $08 ' backspace 49 | ASCII_TAB = $09 ' horizontal tab 50 | ASCII_LF = $0A ' line feed 51 | ASCII_VT = $0B ' vertical tab 52 | ASCII_FF = $0C ' form feed (new page) 53 | ASCII_CR = $0D ' carriage return 54 | 55 | ASCII_ESC = $1B ' escape 56 | 57 | ASCII_SPACE = $20 ' space 58 | ASCII_HASH = $23 ' # 59 | ASCII_COMMA = $2C ' , 60 | ASCII_PERIOD = $2E ' . 61 | 62 | ASCII_SEMI = $3B ' ; 63 | 64 | ASCII_0 = $30 ' 0 65 | ASCII_9 = $39 ' 9 66 | 67 | ASCII_LB = $5B ' [ 68 | ASCII_RB = $5D ' ] 69 | 70 | ASCII_DEL = $7F ' delete 71 | 72 | CON 73 | 74 | ' XMODEM control codes 75 | 76 | XMODEM_SOH = $01 ' Start of Header 77 | XMODEM_EOT = $04 ' End of Transmission 78 | XMODEM_ETB = $17 ' End of Transmission Block 79 | XMODEM_CAN = $18 ' Cancel 80 | 81 | 82 | VAR 83 | 84 | ' ----------------------------------------------------------------------------- 85 | ' DECLARED VARIABLES, ARRAYS, ETC. 86 | ' ----------------------------------------------------------------------------- 87 | 88 | byte gScreenRows, gScreenCols ' convenient globals to store number of screen columns and rows 89 | 90 | ' these data structures contains two cursors in the format [x,y,mode] 91 | ' these are passed to the VGA driver, so it can render them over the text in the display 92 | ' like "hardware" cursors, that don't disturb the graphics under them. We can use them 93 | ' to show where the text cursor and mouse cursor is 94 | ' The data structure is 6 contiguous bytes which we pass to the VGA driver ultimately 95 | 96 | byte gTextCursX, gTextCursY, gTextCursMode ' text cursor 0 [x0,y0,mode0] 97 | byte gMouseCursX, gMouseCursY, gMouseCursMode ' mouse cursor 1 [x1,y1,mode1] (unused but required for VGA driver) 98 | 99 | long gScreenBufferPtr ' holds the address of the video buffer passed back from the VGA driver 100 | 101 | long termStack [64] ' small stack for the serial terminal input cog 102 | 103 | 104 | OBJ 105 | 106 | term : "terminal_ftdi" 107 | kbd : "keyboard_ps2" 108 | wmf : "wmf_terminal_vga" 109 | i2c : "i2c" 110 | acia : "acia_rc2014" 111 | 112 | 113 | PUB main 114 | 115 | 'start the serial terminal 116 | term.start (115200) 117 | term.clear ' clear terminal 118 | term.str (string("UX Module Initialised")) 119 | term.lineFeed 120 | 121 | 'start the ACIA interface 122 | acia.start (PORT_DEFAULT) 'default for RC2014 ROM 123 | ' acia.start (PORT_ROMWBW) 'optional for RomWBW, when used together with SIO/2 Module on 0x80 124 | 125 | 'start the VGA scren 126 | screenInit 127 | 128 | 'start the keyboard 129 | kbd.start (KBD_DATA_PIN, KBD_CLK_PIN) 130 | 131 | 'start i2c 132 | i2c.init (SCL_PIN, SDA_PIN) 133 | 134 | 'start serial processing in a separate cog 135 | cognew (termToZ80, @termStack) 136 | 137 | 'MAIN COG EVENT LOOP - this is where you put all your code in a non-blocking infinite loop... 138 | repeat 139 | ' if no input from keyboard then continue 140 | kbdToZ80 141 | ' if no input from ACIA then continue 142 | readZ80 143 | 144 | 145 | CON 146 | 147 | '' Visual differentiation 148 | 149 | 150 | PUB screenInit | retVal 151 | ' This functions creates the entire user experience and does any other 152 | ' static initialization you might want. 153 | 154 | ' text cursor starting position and as blinking underscore 155 | gTextCursX := 0 156 | gTextCursY := 0 157 | gTextCursMode := %110 158 | 159 | ' set mouse cursor position as off 160 | gMouseCursX := 0 161 | gMouseCursY := 0 162 | gMouseCursMode := 0 163 | 164 | 165 | ' now start the VGA driver and terminal services 166 | retVal := wmf.init (VGA_BASE_PIN, @gTextCursX) 167 | 168 | ' rows encoded in upper 8-bits. columns in lower 8-bits of return value, redundant code really 169 | ' since we pull it in with a constant in the first CON section, but up to you! 170 | gScreenRows := ( retVal & $0000FF00 ) >> 8 171 | gScreenCols := retVal & $000000FF 172 | 173 | ' VGA buffer encoded in upper 16-bits of return value 174 | gScreenBufferPtr := retVal >> 16 175 | 176 | wmf.strScreenLn (string("UX Module Initialised")) 177 | ++gTextCursY 178 | 179 | ' return to caller 180 | return 181 | 182 | 183 | PUB readZ80 | char, n, m 184 | 185 | ' if no input from ACIA or no space in terminal tx buffer then return 186 | repeat while acia.rxCount > 0 and term.txCheck ' check whether any bytes have arrived (with /RTS) 187 | 188 | ' get character from buffer 189 | char := acia.rx 190 | 191 | case char 192 | 193 | XMODEM_SOH: ' XMODEM Start of Header 194 | 195 | term.tx (char) ' SOH to terminal 196 | 197 | n := acia.rx 198 | term.tx (n) ' Packet Number to terminal 199 | 200 | m := acia.rx 201 | term.tx (m) ' Complimented Packet Number to terminal 202 | 203 | if ( n == $FF-m ) 204 | n := 129 ' get another 129 (of 132/133 total) XMODEM packet characters 205 | repeat 206 | term.tx (acia.rx) ' get next characters after Packet Header 207 | while ( --n ) 208 | 209 | ASCII_BS, ASCII_DEL: ' backspace (edit), delete 210 | 211 | ' move cursor back once to overwrite last character on terminal 212 | term.tx (ASCII_BS) 213 | term.tx (ASCII_SPACE) 214 | term.tx (ASCII_BS) 215 | 216 | if ( gTextCursX > 0 ) 217 | --gTextCursX 218 | 219 | ' move cursor back once to overwrite last character on screen 220 | wmf.outScreen (wmf#BS) 221 | wmf.outScreen (wmf#ASCII_SPACE) 222 | wmf.outScreen (wmf#BS) 223 | 224 | ASCII_TAB: ' horizontal Tab 225 | 226 | term.tx (char) 227 | 228 | if ( gTextCursY < gScreenCols-5 ) 229 | repeat 230 | ++gTextCursY 231 | while gTextCursY & 3 232 | 233 | wmf.outScreen (wmf#TB) 234 | 235 | ASCII_LF: ' line feed 236 | 237 | ' eat linefeed from Z80. 238 | next 239 | 240 | ASCII_CR: ' carriage return 241 | 242 | term.lineFeed 243 | 244 | gTextCursX := 0 245 | if ( gTextCursY < gScreenRows-1 ) 246 | ++gTextCursY 247 | 248 | wmf.outScreen (wmf#NL) 249 | 250 | ASCII_ESC: ' escape 251 | 252 | term.tx (char) ' ESC to terminal 253 | 254 | char := acia.rx ' get next character after ESC 255 | term.tx (char) ' possible CSI to terminal 256 | 257 | case char 258 | 259 | ASCII_LB: ' CSI Control Sequence Introducer 260 | 261 | n := 0 262 | 263 | repeat 264 | char := acia.rx ' get next characters after CSI 265 | term.tx (char) ' possible modifier char to terminal 266 | 267 | if ( char => "0" AND char =< "9" ) 268 | n := n*10 + char - ASCII_0 269 | 270 | while ( char => "0" AND char =< "9" ) 271 | 272 | case char 273 | 274 | "A": ' cursor up 275 | if ( n == 0 ) 276 | ++n 277 | if ( gTextCursY > n // gScreenRows - 1 ) 278 | gTextCursY := gTextCursY - n // gScreenRows 279 | wmf.outScreen (wmf#PY) 280 | wmf.outScreen (gTextCursY) 281 | 282 | "B": ' cursor down 283 | if ( n == 0 ) 284 | ++n 285 | if ( gTextCursY < gScreenRows - n // gScreenRows ) 286 | gTextCursY := gTextCursY + n // gScreenRows 287 | wmf.outScreen (wmf#PY) 288 | wmf.outScreen (gTextCursY) 289 | 290 | "C": ' cursor right 291 | if ( n == 0 ) 292 | ++n 293 | if ( gTextCursX < gScreenCols - n // gScreenCols ) 294 | gTextCursX := gTextCursX + n // gScreenCols 295 | wmf.outScreen (wmf#PX) 296 | wmf.outScreen (gTextCursX) 297 | 298 | "D": ' cursor left 299 | if ( n == 0 ) 300 | ++n 301 | if ( gTextCursX > n // gScreenCols - 1 ) 302 | gTextCursX := gTextCursX - n // gScreenCols 303 | wmf.outScreen (wmf#PX) 304 | wmf.outScreen (gTextCursX) 305 | 306 | "E": ' cursor next line n start 307 | if ( n == 0 ) 308 | ++n 309 | if ( gTextCursY < gScreenRows - n // gScreenRows ) 310 | gTextCursY := gTextCursY + n // gScreenRows 311 | gTextCursX := 0 312 | wmf.outScreen (wmf#PY) 313 | wmf.outScreen (gTextCursY) 314 | wmf.outScreen (wmf#PX) 315 | wmf.outScreen (gTextCursX) 316 | 317 | "F": ' cursor previous line n start 318 | if ( n == 0 ) 319 | ++n 320 | if ( gTextCursY > n // gScreenRows - 1 ) 321 | gTextCursY := gTextCursY - n // gScreenRows 322 | gTextCursX := 0 323 | wmf.outScreen (wmf#PY) 324 | wmf.outScreen (gTextCursY) 325 | wmf.outScreen (wmf#PX) 326 | wmf.outScreen (gTextCursX) 327 | 328 | "G": ' cursor to column n 329 | if ( n == 0 ) 330 | ++n 331 | gTextCursX := n // gScreenCols - 1 332 | wmf.outScreen (wmf#PX) 333 | wmf.outScreen (gTextCursX) 334 | 335 | "H": ' cursor to row n, column 1 336 | if ( n == 0 ) 337 | ++n 338 | gTextCursY := n // gScreenRows - 1 339 | gTextCursX := 0 340 | wmf.outScreen (wmf#PY) 341 | wmf.outScreen (gTextCursY) 342 | wmf.outScreen (wmf#PX) 343 | wmf.outScreen (gTextCursX) 344 | 345 | "J": ' clear screen 346 | if ( n == 0 ) 347 | bytefill ( gScreenBufferPtr + gTextCursY*gScreenCols + gTextCursX, ASCII_SPACE, gScreenRows*gScreenCols - gTextCursY*gScreenCols - gTextCursX ) 348 | elseif ( n == 1 ) 349 | bytefill ( gScreenBufferPtr, ASCII_SPACE, gTextCursY*gScreenCols + gTextCursX + 1 ) 350 | elseif ( n == 2 ) 351 | gTextCursX := gTextCursY := 0 352 | wmf.outScreen ( wmf#CS ) 353 | 354 | "K": ' clear line 355 | if ( n == 0 ) 356 | bytefill ( gScreenBufferPtr + gTextCursY*gScreenCols + gTextCursX, ASCII_SPACE, gScreenCols - gTextCursX) 357 | elseif ( n == 1 ) 358 | bytefill ( gScreenBufferPtr + gTextCursY*gScreenCols, ASCII_SPACE, gTextCursX + 1 ) 359 | elseif ( n == 2 ) 360 | bytefill ( gScreenBufferPtr + gTextCursY*gScreenCols, ASCII_SPACE, gScreenCols ) 361 | gTextCursX := 0 362 | wmf.outScreen (wmf#PX) 363 | wmf.outScreen (gTextCursX) 364 | 365 | "m": ' set graphics rendition parameters 366 | if ( n == 0 ) 367 | wmf.setLineColor ( gTextCursY, wmf#CTHEME_DEFAULT_FG, wmf#CTHEME_DEFAULT_BG ) 368 | elseif ( n == 7 ) 369 | wmf.setLineColor ( gTextCursY, wmf#CTHEME_DEFAULT_BG, wmf#CTHEME_DEFAULT_FG ) 370 | 371 | ASCII_SEMI: 372 | 373 | m :=0 374 | 375 | repeat 376 | char := acia.rx ' get next characters after semicolon 377 | term.tx (char) ' possible modifier char to terminal 378 | 379 | if ( char => "0" AND char =< "9" ) 380 | m := m*10 + char - ASCII_0 381 | 382 | while ( char => "0" AND char =< "9" ) 383 | 384 | if ( char == "H" ) ' cursor to row n, column m 385 | if ( n == 0 ) 386 | ++n 387 | if ( m == 0 ) 388 | ++m 389 | gTextCursY := n // gScreenRows - 1 390 | gTextCursX := m // gScreenCols - 1 391 | wmf.outScreen (wmf#PY) 392 | wmf.outScreen (gTextCursY) 393 | wmf.outScreen (wmf#PX) 394 | wmf.outScreen (gTextCursX) 395 | 396 | other: ' all other cases after ESC 397 | if ( char => $20 ) ' only printable characters to the screen 398 | if ( gTextCursX < gScreenCols - 1 ) ' update cursor position 399 | ++gTextCursX 400 | else 401 | if ( gTextCursY < gScreenRows - 1 ) 402 | ++gTextCursY 403 | gTextCursX := 0 404 | wmf.outScreen (char) ' echo printable non CSI character 405 | 406 | other: ' all other cases 407 | 408 | term.tx (char) ' send other characters out the serial terminal 409 | 410 | if ( char => $20 ) ' only printable characters to the screen 411 | if ( gTextCursX < gScreenCols - 1 ) ' update cursor position 412 | ++gTextCursX 413 | else 414 | if ( gTextCursY < gScreenRows - 1 ) 415 | ++gTextCursY 416 | gTextCursX := 0 417 | wmf.outScreen (char) ' echo all printable characters 418 | 419 | 420 | PUB kbdToZ80 | char 421 | 422 | ' if no input from keyboard or no space in acia tx buffer then return 423 | repeat while kbd.gotKey and acia.txCheck 424 | 425 | char := kbd.getKey 426 | 427 | case char 428 | 429 | kbd#KBD_ASCII_BS, kbd#KBD_ASCII_DEL: 430 | acia.tx (ASCII_BS) 431 | 432 | kbd#KBD_ASCII_CR, kbd#KBD_ASCII_PAD_CR: 433 | acia.tx (ASCII_CR) 434 | 435 | kbd#KBD_ASCII_LF: 436 | next 437 | 438 | kbd#KBD_ASCII_ESC: 439 | acia.tx (ASCII_ESC) 440 | 441 | kbd#KBD_ASCII_UP: 442 | acia.txString ( string (ASCII_ESC, "[A") ) 443 | 444 | kbd#KBD_ASCII_DOWN: 445 | acia.txString ( string (ASCII_ESC, "[B") ) 446 | 447 | kbd#KBD_ASCII_RIGHT: 448 | acia.txString ( string (ASCII_ESC, "[C") ) 449 | 450 | kbd#KBD_ASCII_LEFT: 451 | acia.txString ( string (ASCII_ESC, "[D") ) 452 | 453 | kbd#KBD_ASCII_HOME: 454 | acia.txString ( string (ASCII_ESC, "[H") ) 455 | 456 | kbd#KBD_ASCII_CTRL | kbd#KBD_ASCII_ALT | kbd#KBD_ASCII_DEL: 457 | 458 | acia.txFlush ' remove any pending transmit queue to Z80 459 | dira[ acia#RESET_PIN_NUM ]~~ ' set /RESET pin to output to reset the Z80 460 | dira[ acia#RESET_PIN_NUM ]~ ' set /RESET pin to input 461 | 462 | term.clear ' clear the serial terminal 463 | 464 | gTextCursX := gTextCursY := 0 ' move screen cursor to home position 465 | wmf.outScreen ( wmf#CS ) ' clear the screen 466 | 467 | other: ' all other input 468 | acia.tx (char) 469 | 470 | 471 | PUB termToZ80 472 | 473 | 'COG EVENT LOOP - this is where you put all your code in a non-blocking infinite loop... 474 | repeat 475 | ' if no input from terminal then wait till there is 476 | if term.rxCount > 0 and acia.txCheck ' if there is a received byte and space in acia tx buffer 477 | acia.tx (term.rx) ' grab a byte and push it to the tx buffer 478 | 479 | 480 | DAT 481 | 482 | {{ 483 | +------------------------------------------------------------------------------------------------------------------------------+ 484 | | TERMS OF USE: MIT License | 485 | +------------------------------------------------------------------------------------------------------------------------------+ 486 | |Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation | 487 | |files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, | 488 | |modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software| 489 | |is furnished to do so, subject to the following conditions: | 490 | | | 491 | |The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.| 492 | | | 493 | |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 494 | |WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | 495 | |COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 496 | |ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 497 | +------------------------------------------------------------------------------------------------------------------------------+ 498 | }} 499 | --------------------------------------------------------------------------------