├── .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 |
10 |
11 | ## Pictures
12 |
13 |
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 | [](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 |
--------------------------------------------------------------------------------