Compare commits
211 Commits
Author | SHA1 | Date |
---|---|---|
ole00 | 6095042e5a | |
ole00 | 99ccaa302f | |
ole00 | e400da6b10 | |
ole00 | 6c5ffab5be | |
ole00 | b9690e6945 | |
ole00 | 1ac80bbb01 | |
ole00 | 28d8737780 | |
ole00 | 998b1329c8 | |
ole00 | a3e6f11b0f | |
ole00 | 7c0a32cba3 | |
ole00 | cf34c1dfee | |
ole00 | babba5bca9 | |
ole00 | afae1b2166 | |
ole00 | 9656fbadd3 | |
ole00 | 29df84d42e | |
ole00 | e745ae9919 | |
ole00 | 6230e7c55e | |
ole00 | 18b3cea6a2 | |
ole00 | 7d20d778c6 | |
ole00 | fb22c14e9f | |
ole00 | 316d103456 | |
ole00 | cce891c513 | |
ole00 | ad9308e291 | |
ole00 | 32468f6dd8 | |
ole00 | 2b83233399 | |
ole00 | 56b687017a | |
ole00 | c205579e9b | |
ole00 | 7a3981a9b3 | |
ole00 | 54600a153a | |
ole00 | a8ecb518cf | |
ole00 | eac70f6c68 | |
ole00 | 0367a8b127 | |
ole00 | 718a908a9d | |
ole00 | 0e99f07370 | |
ole00 | 5621df2f1f | |
ole00 | b733cd5e6a | |
ole00 | 0761907067 | |
ole00 | a3968f5c00 | |
ole00 | 3b4921daa2 | |
ole00 | 4238800190 | |
ole00 | e9aaf41c48 | |
ole00 | a48de726bf | |
ole00 | 1589119e7c | |
ole00 | 37f93be2d3 | |
ole00 | 757e13e55f | |
ole00 | 52466f64c6 | |
ole00 | a9bf98b719 | |
ole00 | dabfcf5aad | |
ole00 | 79e33ab2a5 | |
ole00 | 2754ff5c47 | |
ole00 | 49342b2174 | |
ole00 | e6d9a6ea2e | |
ole00 | 941142df71 | |
ole00 | 733ea3c8e3 | |
ole00 | 3ee0147d88 | |
ole00 | 103a99ab7a | |
ole00 | 460d0f2caa | |
ole00 | a559e10612 | |
ole00 | e5ffe7ec19 | |
ole00 | 6b6bbd76e2 | |
ole00 | 0b865d4892 | |
ole00 | cc64a29953 | |
ole00 | 7ef0038209 | |
ole00 | 5f2105680f | |
ole00 | e99494df09 | |
ole00 | 053c914fae | |
ole00 | dc16f92a2e | |
ole00 | 7ff02e0a8d | |
ole00 | ba3caf3a15 | |
ole00 | f3147397f9 | |
ole00 | 77a5d7d236 | |
ole00 | b216b16c9a | |
ole00 | bd19c7c776 | |
ole00 | fab07e57fd | |
ole00 | 0cb6434aea | |
ole00 | 31578a6eec | |
ole00 | 00dc5cf8f6 | |
ole00 | 28c4a104d1 | |
HubertH | 8ae5b495f8 | |
HubertH | fcd7b15fe4 | |
HubertH | 0cd9ac9b35 | |
HubertH | 19662a1939 | |
ole00 | 5748ad601b | |
ole00 | 62d66b216b | |
ole00 | 2b1b34f48c | |
ole00 | de1d601992 | |
ole00 | 24494accde | |
ole00 | cefd435b28 | |
rhgndf | ec1e26464f | |
rhgndf | 50bc140928 | |
rhgndf | c7f063b2a9 | |
rhgndf | 5c2cd50d47 | |
rhgndf | 79594dc863 | |
ole00 | e335ee638f | |
ole00 | 4ba672b896 | |
ole00 | e6cf1c1b22 | |
ole00 | a1190dd9d8 | |
ole00 | 472bbffce7 | |
ole00 | b0f2ace6fd | |
rhgndf | 8cbc013e68 | |
rhgndf | b5a7334d59 | |
rhgndf | c7b7f06f10 | |
rhgndf | f5c05e463d | |
rhgndf | 6a288ed68e | |
rhgndf | 2275e13091 | |
rhgndf | b60f36b144 | |
ole00 | 7944dbf2c1 | |
ole00 | f63ae40bb4 | |
ole00 | a1fc6bb2f7 | |
ole00 | 92d8c72f1f | |
ole00 | 95e461233e | |
ole00 | 76ab0afdda | |
ole00 | 93bcf40dd0 | |
ole00 | 3e0a2ad357 | |
ole00 | b596f7d9d1 | |
ole00 | 08e3cea5c7 | |
ole00 | 7cb4aaa5db | |
rhgndf | a36c425569 | |
rhgndf | ab9fa88437 | |
rhgndf | a1bbbdff24 | |
rhgndf | e7ceab90c1 | |
rhgndf | 322bc2837c | |
rhgndf | 5a3e1f7c75 | |
rhgndf | 8f995e1c9f | |
rhgndf | c89331138e | |
rhgndf | b160a49601 | |
ole00 | 13bc7bdad9 | |
ole00 | 4b186fbe74 | |
ole00 | b498bc73f3 | |
ole00 | 6beae4de9c | |
ole00 | 711da82260 | |
rhgndf | d26234d6ca | |
rhgndf | 393c03993b | |
ole00 | 3fc8e93940 | |
rhgndf | 14b36093c1 | |
rhgndf | e9b6eae0ce | |
rhgndf | 1f5a856f2a | |
rhgndf | ae05e4d51b | |
ole00 | d95268e8ba | |
ole00 | 8b82d0ea0e | |
ole00 | 4f1a89007b | |
ole00 | 37c5cbd12b | |
rhgndf | 1ccfec7012 | |
rhgndf | 7a93bac034 | |
rhgndf | c97f4297c1 | |
rhgndf | 39b27c3cac | |
rhgndf | 78eb638c98 | |
rhgndf | bb8f67fe74 | |
rhgndf | f0c572bc33 | |
rhgndf | 534b50518f | |
rhgndf | 7b08a1a749 | |
ole00 | 5aaa1bdf8c | |
ole00 | f3ffd7f0e1 | |
rhgndf | 87a77ad4af | |
rhgndf | 4145612445 | |
rhgndf | cd410666f0 | |
rhgndf | 82b6691bba | |
rhgndf | 5dc3f793f4 | |
rhgndf | f2ae8e2391 | |
ole00 | 47432b8c05 | |
ole00 | f19a4e1eca | |
ole00 | 0019e89643 | |
ole00 | 07d9e67749 | |
ole00 | 12fb6a8ddc | |
ole00 | 86a4ade9f9 | |
ole00 | d3acb78576 | |
ole00 | c4487a99da | |
ole00 | 0df11718b7 | |
ole00 | 2006182094 | |
ole00 | 30430abfbf | |
ole00 | 09148d9d1b | |
ole00 | 90f107f33e | |
ole00 | 9bc3c889a2 | |
ole00 | c16e145f83 | |
ole00 | 1fa2d8c5fd | |
ole00 | cff8fb40a7 | |
ole00 | 4d98e66cbc | |
ole00 | fae2d96e7e | |
ole00 | 4bb44e8ac3 | |
ole00 | 70c29929ce | |
ole00 | 97f8ece5af | |
ole00 | 4c27435161 | |
ole00 | 325b51d722 | |
ole00 | 7ed84ffa63 | |
ole00 | f9660f8eaf | |
ole00 | 30f4590d4e | |
ole00 | 4e3d4dafd9 | |
ole00 | 80d40e24a3 | |
ole00 | 5bcb23f1a2 | |
ole00 | 8d12ec9e58 | |
ole00 | 7d332acae6 | |
ole00 | 4db4108d4a | |
ole00 | 48982f241a | |
ole00 | 7774c76626 | |
ole00 | 7b9ccc9f8d | |
ole00 | 1a3a009885 | |
ole00 | c67ced85e7 | |
ole00 | 76a5d7fa9c | |
ole00 | c6087fdfed | |
ole00 | 45f7fea022 | |
ole00 | 65443dd5f2 | |
ole00 | 81382a0e91 | |
ole00 | 630851857a | |
ole00 | e9d005213e | |
ole00 | 317b3520d8 | |
ole00 | ba15a74dee | |
ole00 | ffa637eb8e | |
ole00 | f48513f05b | |
ole00 | 1dc2836125 | |
ole00 | 45eb04de80 | |
ole00 | d393e0fcc8 |
|
@ -4,4 +4,7 @@
|
|||
afterburner
|
||||
misc
|
||||
*.exe
|
||||
|
||||
*.pld
|
||||
*.PLD
|
||||
*.JED
|
||||
*.zip
|
||||
|
|
349
README.md
|
@ -1,69 +1,155 @@
|
|||
# afterburner
|
||||
GAL chip programmer for Arduino
|
||||
![Board image](https://github.com/ole00/afterburner/raw/master/img/afterburner_small.jpg "afterburner")
|
||||
![Board image](https://github.com/ole00/afterburner/raw/master/img/afterburner_new_design.jpg "afterburner")
|
||||
|
||||
This is a GAL IC programmer software that allows to program GAL IC chips
|
||||
from various manfucaturers. It is based on work of several other people:
|
||||
from various manufcaturers. It is based on work of several other people:
|
||||
|
||||
Bruce Abbott:
|
||||
https://web.archive.org/web/20220121030038/http://www.bhabbott.net.nz/atfblast.html
|
||||
|
||||
Manfred Winterhoff:
|
||||
http://www.armory.com/%7Erstevew/Public/Pgmrs/GAL/_ClikMe1st.htm
|
||||
|
||||
Yorck Thiele:
|
||||
https://www.ythiee.com/2021/06/06/galmate-hardware/
|
||||
|
||||
Michael Dreher:
|
||||
https://github.com/nospam2000/afterburner.git
|
||||
|
||||
Marcelo Roberto Jimenez: (JTAG player)
|
||||
https://github.com/mrjimenez/JTAG
|
||||
|
||||
whitequark · it: (ATF150X jed to svf tool)
|
||||
https://github.com/whitequark/prjbureau
|
||||
|
||||
OpenOCD: (svf to xsvf tool)
|
||||
https://github.com/arduino/OpenOCD/blob/master/contrib/xsvf_tools/svf2xsvf.py
|
||||
|
||||
who did the most of the hard work of deciphering and publishing the programming
|
||||
protocol of these chips. Their programs were Windows based and relied on
|
||||
protocol of these chips. Some of their early programs were Windows based and relied on
|
||||
presence of parallel port (LPT). Afterburner was written for Linux OS
|
||||
(also works on Win32/64, Mac OSX64), and requires serial connection to
|
||||
Arduio UNO, which does the programming of the GAL chip.
|
||||
Arduino UNO, which does the programming of the GAL chip.
|
||||
|
||||
**Update: ver.0.6.0 added experimental support for ATF1502AS and ATF1504AS. Only
|
||||
identify, erase and write commands are supported. Read function is unsupported.
|
||||
Verification is usually done automatically - it is a part of the .xsvf JTAG file
|
||||
which is used when writing the design. See Discussions for more information**
|
||||
|
||||
**Update: ver.0.5.8 improved calibration alogrithm and resolution for mcp4151 digi pot.
|
||||
Please re-calibrate your Afterburner as the previsouly stored calibration data are invalid.**
|
||||
|
||||
Supported GAL chips:
|
||||
---------------------
|
||||
|
||||
* Atmel ATF16V8B, ATF16V8BQL, ATF22V10B, ATF22V10CQZ
|
||||
* Lattice GAL16V8A, GAL16V8B, GAL16V8D
|
||||
* Lattice GAL22V10B
|
||||
* National GAL16V8
|
||||
* Lattice GAL20V8B via [adapter board](https://github.com/ole00/afterburner/raw/master/img/gal20v8_adapter.png)
|
||||
| | Atmel | Lattice | National | ST |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 16V8 | ATF16V8B, ATF16V8BQL, ATF16V8C | GAL16V8A, GAL16V8B, GAL16V8D | GAL16V8 | GAL16V8 |
|
||||
| 18V10 | - | GAL18V10, GAL18V10B[1] | - | - |
|
||||
| 20V8 | ATF20V8B | GAL20V8B | GAL20V8 | - |
|
||||
| 20RA10 | - | GAL20RA10, GAL20RA10B | - | - |
|
||||
| 20XV10 | - | GAL20XV10B | - | - |
|
||||
| 22V10 | ATF22V10B, ATF22V10C, ATF22V10CQZ | GAL22V10B, GAL22V10D | - | - |
|
||||
| 6001 | - | GAL6001B | - | - |
|
||||
| 6002 | - | GAL6002B | - | - |
|
||||
| 26CV12 | - | GAL26CV12B[2] | - | - |
|
||||
| 26V12 | - | GAL26V12C[2] | - | - |
|
||||
| 750 | ATF750C | - | - | - |
|
||||
| 150X | ATF1502AS, ATF1502ASL, ATF1504AS, ATF1504ASL[2][3] | - | - | - |
|
||||
|
||||
**Please note that ATF16V8C or ATF16V8CZ are not currently supported.** Yes the B/C at the end of the part designator seems like a minor thing but in fact the programming protocol seems to be different compared to the B version (which is supported). Keep it in mind when ordering parts.
|
||||
|
||||
**Update 25/05/2020:** there was an issue programming the ATF16V8B with afterburner. This is now fixed, but the arduino code needs to be recompiled and uploaded to your arduino in order to properly support ATF16V8B IC. The PC software does not need recompilation or update for this fix to work. Credits go to mecparts for the fix and PerroLoco64 for the bug report.
|
||||
[1]: requires PCB v.3.1 or modified PCB v.3.0 - see Troubleshooting
|
||||
[2]: requires adapter - see gerbers, pcb and img directory
|
||||
[3]: also supports 3.3V ATF1502ASV and ATF1504ASV when Arduino IOREF is 3.3V (ARM or ESP32 based Arduinos or Arduinos with IOREF 3.3V switch)
|
||||
|
||||
[-]: - represents either this combination does not exist or hasn't been tested yet. Testers are welcome to report their findings.
|
||||
|
||||
**This is a new Afterburner design with variable programming voltage control and with single ZIF socket for 20 and 24 pin GAL chips.**
|
||||
The PC software is backward compatible with the older Afterburner desgin/boards.
|
||||
You can still access the older/simpler ![design here](https://github.com/ole00/afterburner/tree/version_4_legacy "Afterburner legacy")
|
||||
|
||||
|
||||
The new design features:
|
||||
|
||||
* variable programming voltage control via digital potentiometer
|
||||
* single 24 pin ZIF socket for 16V8, 20V8 and 22V10 GALs. The adapter for GAL20V8 is no longer needed.
|
||||
* simpler connection to MT3608 module (no need to modify the module)
|
||||
* both Through Hole and SMT footprints present on a single PCB. This allows
|
||||
to mix & match SMT and TH parts based on your skills and components availability.
|
||||
|
||||
Drawbacks compared to the old Afterburner design:
|
||||
|
||||
* more parts required, most notably the digital pot MCP4131 and a shift register 74hc595
|
||||
* a few more steps during initial VPP calibration. But once the calibration is done it does not need to be changed for different GAL chips.
|
||||
* the PCB design for etched board is no longer provided because of the higher complexity. Please use a PCB fabrication service or use the older Afterburner design (see above).
|
||||
|
||||
|
||||
Setup:
|
||||
* Upload the afterburner.ino sketch to your Arduino UNO.
|
||||
---------------------
|
||||
|
||||
* Connect the pins of the GAL chip to Arduino UNO according to
|
||||
the schematics images. Ideally use a PCB (ether etched or made
|
||||
in a fab) that's provided in 'pcb' and 'gerbers' directory.
|
||||
You can also hardwire on protoboard or breadboard.
|
||||
* Upload the afterburner.ino sketch to your Arduino UNO. Use Arduino IDE to upload the sketch, both IDE version 1.8.X and 2.X should work.
|
||||
|
||||
* Build the Afterburner hardware. Buy the PCB from the an online PCB production service (use provided gerber archive in 'gerbers' directory). Then solder the components on the PCB - check the schematic.pdf and BOM.txt for parts list.
|
||||
|
||||
* Compile the afteburner.c to get afterburner executable. Run
|
||||
./compile.sh to do that.
|
||||
./compile.sh to do that. Alternatively use the precompiled binaries in the 'releases' directory.
|
||||
|
||||
* Set the programming voltage (VPP) on the voltage up-converter
|
||||
module (MT3608) depending on the GAL chip
|
||||
- Atmel ATF16V8B: 10V
|
||||
- Lattice GAL16V8: 10V, also works with 12V
|
||||
- Others - between 10 - 14V - untested
|
||||
* Calibrate the variable voltage. This needs to be done only once, before you start using Afterburner for programming GAL chips.
|
||||
Calibration procedure differs a little bit when using MT3608 module or when using on board voltage booster.
|
||||
|
||||
* Check the programming voltage (VPP) without the GAL chip being
|
||||
inserted / connected to Arduino UNO. Test the voltage on MT3608
|
||||
module VOUT- and VOUT+ pins while running the following command:
|
||||
**When using MT3608 module**
|
||||
|
||||
* **Calibration step 1)** Turn the small potentiometer (R9) on the Afterburner to the middle position. This pot acts as compensation resistor for the digital pot.
|
||||
|
||||
* **Calibration step 2)** Set the programming voltage (VPP) to 16.5V: Check the programming voltage (VPP) without the GAL chip being inserted / connected to Afterburner. Test the voltage on MT3608 module VOUT- and VOUT+ pins while running the following command:
|
||||
<pre>
|
||||
./afterburner s
|
||||
</pre>
|
||||
|
||||
* Check the chip identification by runnig the following command:
|
||||
While the command is running turn the pot on the MT3608 module (not the Afterburner's pot) counter clockwise (5 to 20 full turns). The VPP voltage should be displayed on the console, but for the very first setup use a multimeter to verify the VPP voltage as well.
|
||||
Re-run the command (if needed) to give you more time to set the 16.5V VPP.
|
||||
|
||||
* **Calibration step 3)** This step scans the available voltages and records the pot taps. Run the following command:
|
||||
<pre>
|
||||
./afterburner b
|
||||
</pre>
|
||||
You will see several messages on the console. Check the one with '*Index for VPP 900 is'. This is the lowest supported VPP of 9V and the index should ideally be between 30 and 70, but if it a bit less or a bit higher (let's say from 20 to 90) the calibration should still be valid.
|
||||
If you see a significantly different index value (lower or higher) move the Afterburner's compensation pot (R9) either a bit lower or higher (depending on the VPP 900 index value) and go back to Calibration step 2). Repeat the Calibration steps 2) and 3) until you find the good value on VPP 900 index. If everything goes OK the last VPP index (VPP 1650) should be 255. If it is not exactly 255, but at least above 250 then it is fine.
|
||||
|
||||
* **Calibration step 4)** Measure the actual VPP to verify the value read by Arduino is correct. Run the following command while measuring the VPP on your multimeter:
|
||||
<pre>
|
||||
./afterburner m
|
||||
</pre>
|
||||
Afterburner will set the VPP to several values (5V, 9V, 12V, 14V, 16V) and print the voltage readings as read by Arduinos's ADC. These values should match with readings from your multimeter (except for the 5V which is OK if it is a value from 4.2V - 5.0 V). Important are the values of the higher voltages. If they are off by more than +/-0.05V then you can set the calibration offset by running Calibration step 3) with an extra parameter '-co X':
|
||||
<pre>
|
||||
./afterburner b -co X
|
||||
</pre>
|
||||
Where X is a number from -32 (representing -0.32V offset) to value 32 (representing +0.32V offset). If your multimeter reads 12.1V and the reading on the text console shows 12.00V you need to set positive offset of +0.1V ('-co 10'). If your multimeter reads 11.85V and the reading on the text console shows 12.05V you need to set negative offset of -0.2V ('-co -20'). After setting the calibration offset, the readings on your multimeter should ideally read the same values as the text on the console (+/- 0.05V). The calibration is then done. If (when specifying negative offset value) the calibration fails, turn the MT3608 Pot about 10-15 degrees counter-clockwise (to rise the VPP a tiny bit) and re-do the Calibration step 3.
|
||||
|
||||
* Note that if you use your calibrated Afterburner board with a different Arduino (made by a different company or slightly different design), you may need to re-do the calibration.
|
||||
|
||||
**When using on-board voltage booster:**
|
||||
|
||||
Calibration steps are the same as for MT3608 module with these differences
|
||||
|
||||
* **Calibration Step 2)** We can't turn the extra pot on the MT3608 module, but we can
|
||||
adjust the voltage by turning the R9 pot on the Afterburner PCB. It's OK to have
|
||||
the voltage a bit higher like 16.6V or so in this calibration step.
|
||||
|
||||
* **Calibration Step 3)** Because of the feedback resistance difference compared to MT3608
|
||||
module the calibration index for 9V will be around value 150.
|
||||
|
||||
**GAL chip operations:**
|
||||
* With the GAL chip inserted and power button pressed (or in ON position) check the chip identification by running the following command:
|
||||
<pre>
|
||||
./afterburner i -t [GAL_type]
|
||||
</pre>
|
||||
|
||||
If you get some meaningfull GAL chip identification like:
|
||||
If you get some meaningful GAL chip identification like:
|
||||
<pre>
|
||||
PES info: Atmel ATF16V8B VPP=10.0 Timing: prog=10 erase=25
|
||||
</pre>
|
||||
then all should be well and you can try to erase the chip and then
|
||||
programm it to contain your .jed file.
|
||||
then all should be well and you can try to erase the chip and then program it to contain your .jed file.
|
||||
|
||||
If you get an unknown chip identification like:
|
||||
<pre>
|
||||
|
@ -93,24 +179,24 @@ Setup:
|
|||
./afterburner wv -t [GAL type] -f my_new_gal.jed
|
||||
</pre>
|
||||
|
||||
* If you are not sure which GAL type strings are accepted by Afterburner, simply set a wrong type and it will print the list of supported types:
|
||||
<pre>
|
||||
./afterburner wv -t WHICH
|
||||
</pre>
|
||||
|
||||
How aferburner works:
|
||||
---------------------
|
||||
- PC code reads and parses .jed files, then produces a binary which
|
||||
can be then uploaded to Arduino via serial port. By default
|
||||
/dev/ttyUSB0 is used, but that can be changed to any other device
|
||||
by passing the following option to afterburner:
|
||||
- PC code reads and parses .jed files, then uploads the data to Arduino via serial port. By default /dev/ttyUSB0 is used, but that can be changed to any other serial port device by passing the following option to afterburner:
|
||||
<pre>
|
||||
-d /my/serial/device
|
||||
</pre>
|
||||
|
||||
- PC code of afterburner communicates with Arduino UNO's afterburner
|
||||
sketch by a trivial text based protocol. You can also connect directly
|
||||
to Arduino UNO via serial terminal of your choice and issue some basic
|
||||
commands manually.
|
||||
sketch by a trivial text based protocol to run certain commands (like erase, read, write, upload data etc.). If you are curious, you can also connect directly to Arduino UNO via serial terminal and issue some basic commands manually.
|
||||
|
||||
- Arduino UNO's afterburner sketch does 2 things:
|
||||
* parses commands and data sent from the PC afterburner code
|
||||
* toggles the GPIO pins and drives programming of the GAL content
|
||||
* parses commands and data sent from the PC afterburner app
|
||||
* toggles the GPIO pins and drives programming of the GAL contents
|
||||
|
||||
- more information about GAL chips and their programming can be found here:
|
||||
|
||||
|
@ -121,82 +207,85 @@ How aferburner works:
|
|||
|
||||
PCB:
|
||||
---------------
|
||||
If you decide to use a PCB rather than making breadboard or protoboard
|
||||
build, then you have several options.
|
||||
- Etch your own PCB.
|
||||
* The etching design is stored in 'pcb' directory, use
|
||||
afterburner_etch_1200dpi_bot.png file to transfer the design to the
|
||||
copper board.
|
||||
* It's a single sided design, but you'll have to patch 3
|
||||
traces. See the the combined image where the patch traces are highlighted
|
||||
in blue color. Two short patch wires are located near the top left corner,
|
||||
the last one, slightly longer, is located underneath the MT3608 module.
|
||||
* Resistors are not through hole but smt 1206 package to reduce drilling.
|
||||
* The copper is on the bottom side, to make it easy to solder the socket
|
||||
and capacitors. However, that makes it a bit complicated to solder the Arduino
|
||||
pins. What needs to be done is to push the pins from the top part of the board
|
||||
(side without copper) so that the metal bits are flush with the plastic which keeps
|
||||
the pins together (plastic on the top), then solder the pins on the bottom side. You
|
||||
may then take off the plastic from the top side and slide it in from the bottom side.
|
||||
* You may need to flip the image before the transfer to the copper board, because
|
||||
the copper is on the bottom side.
|
||||
The new design no longer has an etched PCB design available. The most convenient way to get the PCB is to order it online on jlcpcb.com, pcbway.com, allpcb.com or other online services. Use the zip archive stored in the gerbers directory and upload it to the manufacturer's site of your choice.
|
||||
Upload the afterburner_fab_3_0.zip and set the following parameters (if required).
|
||||
|
||||
- Order it online on jlcpcb.com, pcbway.com, allpcb.com etc. Use one of the zip archive
|
||||
stored in the gerbers directory and upload it to the manufacturesr's site of your choice.
|
||||
Use fab_1_2.zip for smaller PCB design that allows to program 16V8 devices only.
|
||||
Use fab_2_1.zip for a bigger design that allows to program 16V8 and 22V10 devices.
|
||||
The price difference should be minimal as both designs fit within 100x100 mm area.
|
||||
|
||||
* Dimensions of the fab_1_1 board is 55x53 mm
|
||||
* Dimensions of the fab_2_0 board is 57*72 mm
|
||||
* Dimensions are 85x54 mm
|
||||
* 2 layer board
|
||||
* PCB Thickness: 1.6, or 1.2
|
||||
* Copper Weight: 1
|
||||
* The rest of the options can stay default or choose whatever you fancy (colors, finish etc.)
|
||||
|
||||
Soldering steps:
|
||||
----------------
|
||||
* check which type of components you have, you can mix and match SMT and through hole components as most of the footprints are doubled to accommodate different parts.
|
||||
* **Important:** C5, C6 and C7 are VPP decoupling capacitors and must be rated to **at least 25V!** You can use 50V rated caps, but do not use 16V or lower ratings.
|
||||
* Even though C5 (10uF, 25V) offers a SMT footprint, I used a through hole part because it reduces the VPP swings better than my SMT cap.
|
||||
* start with the smallest parts, solder the resistors and small capacitors.
|
||||
* solder the two ICS: U1 (digital pot) and U2 (shift register)
|
||||
* solder the LED, the switch and the big capacitors
|
||||
|
||||
**When using MT3608 module**
|
||||
* do **not** solder any components in voltage booster area
|
||||
* **special step** solder a thin wire between the MT3608 module and the PCB hole marked as POT. See the image bellow.
|
||||
* **Important** after you solder the wire measure the resistance between the wire's connection on Afterburner PCB and ground (use TP GND hole) - see red dots
|
||||
on the picture beelow. It must be around 12.5 kilo Ohm. If it is very low value then you made a short while soldering the wire. Fix/remove the short
|
||||
or else the MT3608 will be damaged when it is turned on on.
|
||||
![POT wire image.](https://github.com/ole00/afterburner/raw/master/img/mt3608_wire.jpg "POT wire")
|
||||
* solder the MT3608 module - the POT connection wire must be already soldered!
|
||||
|
||||
**When using on-board voltage booster**
|
||||
* solder the parts in the voltage booster area. Start with the U3 IC - the SOT-23-6 package - so that you have plenty
|
||||
of room for soldering the small IC. Use a flux to ensure the solder melts nicely on the pads.
|
||||
* solder the inductor L1 and diode D2. Ensure D2 polarity is correct - the stripe is on the left side (see photos if unsure).
|
||||
* solder the C10 cap and the resistors. There is no need to solder R10, R11, R12 if you are using the alternative booster IC
|
||||
with SOT-23-5 package (without OVP)
|
||||
* no extra wire is required (the wire is only required when using MT3608 module)
|
||||
|
||||
**After soldering the voltage booster**
|
||||
* calibrate the board. See calibration steps in the Setup section.
|
||||
* solder the ZIF socket
|
||||
|
||||
|
||||
MT3608 modules:
|
||||
---------------
|
||||
* On PCB version 3.2 (or higher) the MT3608 can be replaced by discrete parts soldered on the board. Therefore, if you want to avoid possible issues with
|
||||
MT3608 modules, solder the discreate parts instead of the module. If you are not comfortable soldering SOT-23-6 SMT IC package, then use the MT3608 module.
|
||||
* There is a report some of the MT3608 modules / clones are not compatible with Afterburner. Thanks @meup for the information.
|
||||
* The incompatible MT3608 'clone' causes calibration issue and basically breaks the variable voltage functionality. This can be fixed by replacing the 2k2 resistor located on the module by a 15k resistor.
|
||||
* Bellow is the image of the old (compatible without a mod) and new (require the resistor mod) MT3608 modules. If you happen to have the incompatible module here are the steps to replace the resistor:
|
||||
- heat up a soldering iron to ~350 deg C and put a medium sized solder blob on its tip
|
||||
- touch the tip of the iron in the middle of the resistor for a second
|
||||
- gently press on the resistor and slide it off the PCB.
|
||||
- the resistor footprint allows to solder new SMT or through hole resistor
|
||||
|
||||
![mt3608_modules](https://github.com/ole00/afterburner/raw/master/img/mt3608_modules.jpg "mt3608_modules")
|
||||
|
||||
Troubleshooting:
|
||||
----------------
|
||||
- it does not work!
|
||||
|
||||
* double check the schematics and the connection between Arduino UNO and
|
||||
the GAL chip.
|
||||
* double check the solder joints on the PCB, ensure they are soldered. Especially SMT soldering when done manually can accidentally miss some of the pads.
|
||||
|
||||
* ensure the GAL chip is inserted to the IC socket the right way (check
|
||||
the pin 1 location)
|
||||
the pin 1 location). Note that the 16V8 GALs have to be inserted close to the ZIF lever - see the title image above.
|
||||
|
||||
* ensure the VPP is set correctly on the MT3608 module. If unsure which
|
||||
voltage to use then try individual voltages one by one:
|
||||
10V, 11V, 12V, 13V, 14V, 15V. Do not go beyond 15V as you may damage the
|
||||
GAL chip.
|
||||
|
||||
* measure the VPP only when the GAL chip is physically DISCONNECTED (taken
|
||||
out of the afterburner socket). Some brands of the GAL chip (Atmel) - when
|
||||
connected - iternally lower the voltage on the Edit (VPP) pin (voltage divider?)
|
||||
and such voltage reading is misleading.
|
||||
|
||||
* use an external power supply for your Arduino UNO, powering
|
||||
just via serial USB cable may not be sufficient for driving the GAL chip and the
|
||||
voltage up-converter
|
||||
* ensure the VPP is set correctly on the MT3608 module. Ensure you've gone through all the calibration steps (commands: 's' then 'b' and 'm') and calibration is correct. See the Setup section.
|
||||
|
||||
- I've set the VPP voltage to 14 V, put the chip into the Ziff socket, turned on
|
||||
the power switch then run Afterburner with the 'i' command. My Arduino made a tiny
|
||||
short buzzing noise and then reset itself. What went wrong ?
|
||||
|
||||
* most likely the VPP is set too high and the IC does not like that, it pulls the VPP
|
||||
pin down several times causing the Arduino to reset on brown out. Solution: reduce the
|
||||
VPP voltage by turning the pot clockwise on the MT3608 module.
|
||||
|
||||
* this happens for example on ATF devices when VPP is set to 12V. ATF should use VPP
|
||||
set to 10V when programmed by Afterburner.
|
||||
- what is the Push switch used for? When do I use it?
|
||||
* Normally, the button should be in the Off position (LED is not lit). Also when inserting
|
||||
the GAL chip or when removing the GAL chip from the ZIF socket the switch should be Off.
|
||||
* When using Afterburner's PC app with commands to Identify (i), Read or Verify (r, v) or
|
||||
Write (w) the switch has to be On (LED is lit).
|
||||
* So in general: insert the GAL when the switch is Off, then turn the switch On, run the
|
||||
PC app command. When finished turn the switch Off, remove the GAL chip from the socket.
|
||||
|
||||
- afterburner reports it can not connect to /dev/ttyUSB0, permission denied
|
||||
|
||||
* ensure your user is member of the of the dialup group or alernatively run
|
||||
* ensure your user is member of the of the dialup group or alternatively run
|
||||
afterburner as superuser (use: sudo ./afterburner ...)
|
||||
|
||||
* ensure no other programm on your PC uses that serial port. Close putty, minicom or other
|
||||
* ensure no other program on your PC uses that serial port. Close putty, minicom or other
|
||||
terminals you may be running.
|
||||
|
||||
- afterburner fails to connect to /dev/ttyUSB0
|
||||
|
@ -207,12 +296,20 @@ Troubleshooting:
|
|||
ls -alF /dev/ttyUSB*
|
||||
</pre>
|
||||
|
||||
- my MT3608 module does not have EN pin
|
||||
- I can't program GAL18V10
|
||||
* You'll need PCB version 3.1. If you have PCB version 3.0 you can mod it.
|
||||
See ![here](https://github.com/ole00/afterburner/pull/36) for more information about the mod.
|
||||
* Some GAL18V10B from Aliexpress do not work with Afterburner (fakes? damaged?).
|
||||
My GAL18V10B-15LP from Aliexpress do not work. However, GAL18V10B-**20LP** do work OK (also from Aliexpress).
|
||||
|
||||
* that's unfortanetly a common problem. You have to mod the module as follows:
|
||||
- I want to program ATF16V8C, but it is not listed as supported by the PC app.
|
||||
* use parameter '-t ATF16V8B'. Afterburner finds out it is a C version.
|
||||
|
||||
* cut the PCB trace between pin 4 & 5 of the MT3608 chip. Verify the trace
|
||||
is cut by continuity probe (no beep is audible) between pins 4 & 5.
|
||||
- I forgot to solder the POT wire to the MT3608 module. The MT3608 is already soldered and I can't reach underneath the module to solder the wire.
|
||||
|
||||
* you can either desolder the module by using soldering wick (to remove all solder on the connection pins on the MT3608 module). Then use a low temperature melting solder (like Quick Chip or similar) on the connection joints to loosen up the module. Clean the residues of the low melting solder with soldering wick. Then solder the POT wire and solder the chip back on the PCB. The drawback of this method is that if you use excessive heat during desoldering you can damage the MT3608 module (I've done that). If the module is damaged, it will produce a magic smoke next time the board is turned on. If that happens, desolder the module, use a new module (don't forget to solder the POT wire) and solder it on the board.
|
||||
|
||||
* Another option is to connect the POT wire directly to the MT3608 IC's Feedback (FB) pin 3. This is quite delicate as the IC pins are quite small. Before connecting the power, **ensure the pin 2 and pin 3 are not bridged!**
|
||||
|
||||
<pre>
|
||||
| Blue Potentiometer |
|
||||
|
@ -223,43 +320,44 @@ Troubleshooting:
|
|||
| |______________|
|
||||
|
|
||||
| 3 2 1
|
||||
| | | |
|
||||
|-> | | | MT3608 MODULE
|
||||
| +-------+
|
||||
| | |
|
||||
| |4 5 |
|
||||
| +-------+
|
||||
| |X | |
|
||||
| | | |
|
||||
|
|
||||
|<-- left long edge of the module
|
||||
</pre>
|
||||
|
||||
* X marks the spot - here make the vertical cut. Do not cut the pins
|
||||
itself! Just cut the trace between the pins, which is only barely visible
|
||||
without magnification.
|
||||
|
||||
* solder a thin keynar wire to pin 4 which is your ENable pin.
|
||||
|
||||
![See the MT3608 image in img directory for more details.](https://github.com/ole00/afterburner/raw/master/img/mt3608_mod.jpg "EN pin mod")
|
||||
|
||||
|
||||
* Once that is done, toggling the EN pin will change the output voltage
|
||||
of the module between 5V (actually slightly less than that) and the
|
||||
voltage set by the potentiometer (10V and more).
|
||||
* The small arrow (->) in the above diagram marks the pin where the wire has to be soldered.
|
||||
|
||||
- my MT3608 module does not seem to work - turning the pot does nothing
|
||||
|
||||
* The pot needs to be turned at least 10 revolutions counter-clockwise
|
||||
to do anything useful. Keep trying.
|
||||
to do anything useful. Keep turning.
|
||||
|
||||
- where to get the MT3608 module ?
|
||||
|
||||
* usual places: ebay, aliexpress
|
||||
* **IMPORTANT - check the module compatibility - there are some incompatible modules (see above)**
|
||||
|
||||
- how to run afterburner on Win32, Win64 or MacOSX ?
|
||||
* the same way as on Linux: compile the source code
|
||||
* OR use pre-compiled afterburner binaries located in 'releases' directory
|
||||
* then run afterburner in terminal (use 'cmd' on WinXX) as described above
|
||||
* ensure your serial device name is passed via '-d' option. For example -d COM5 on WinXX
|
||||
* ensure your serial device name is passed via '-d' option. For example -d COM5 on WinXX
|
||||
|
||||
- I have the older Afterburner PCB design, can I use the new PC software and Arduino sketch?
|
||||
* Yes, both programs are compatible with the old Afterburner boards (1.X and 2.X).
|
||||
|
||||
- how do I program ATF150X ICs? They do not fit into the ZIF Socket.
|
||||
There are 2 options. Either use PLCC44 IC package along with the ZIF socket adapter (see the gerber and
|
||||
pcb directory). Or you can program the ATF150X on your target board when using JTAG interface.
|
||||
See this schematics for information about JTAPG pins on ATF150X ICs:
|
||||
http://matthieu.benoit.free.fr/all03/adp/HiLo_ADP-ATF1504.PDF
|
||||
The OGI pin in the schematic is VPP (or EDIT) pin on afterburner. See afterburner schematics
|
||||
how to connect JTAG pins from the ZIF socket into the JTAG pins on your board.
|
||||
|
||||
- what are the .jed files and how to produce them
|
||||
|
||||
|
@ -270,15 +368,36 @@ Troubleshooting:
|
|||
* WinCUPL User's manual: http://ww1.microchip.com/downloads/en/DeviceDoc/doc0737.pdf
|
||||
|
||||
* Try GAL Asm to produce .jed files - see link bellow.
|
||||
|
||||
- can I use .jed files with ATF150X IC?
|
||||
* Not directly. You have to convert the .jed file into .xsvf format. Use the python tools located in the utils/jtag
|
||||
subdirectory to do that. See readme.txt in that directory for more info. Once you convert the .jed to .xsvf
|
||||
you can use it with afterburner like that:
|
||||
<pre>
|
||||
./afterburner -t ATF1502AS -f mydesign.xsvf ew
|
||||
</pre>
|
||||
which will erase the chip and then write your design into the IC.
|
||||
See discussion #64 (ATF1502AS(L) and ATF1504AS(L) support) for more inofrmation.
|
||||
|
||||
|
||||
Other GAL related links:
|
||||
------------------------
|
||||
- GAL chip info: https://k1.spdns.de/Develop/Projects/GalAsm/info/galer/gal16_20v8.html
|
||||
|
||||
- GAL chip programming protocol info: https://k1.spdns.de/Develop/Projects/GalAsm/info/galer/proggal.html
|
||||
|
||||
- GALmate: another open source GAL programmer: https://www.ythiee.com/2021/06/06/galmate-hardware/
|
||||
|
||||
- JDEC file standard 3A: https://k1.spdns.de/Develop/Projects/GalAsm/info/JEDEC%20File%20Standard%203A.txt
|
||||
|
||||
- GAL Asm : https://github.com/dwery/galasm
|
||||
|
||||
- GAL Asm online compiler: https://rhgndf.github.io/galasm-web/
|
||||
|
||||
- PLD and GAL info: https://github.com/peterzieba/5Vpld
|
||||
|
||||
- Fusemap info:
|
||||
* https://blog.frankdecaire.com/2017/01/22/generic-array-logic-devices/
|
||||
* https://blog.frankdecaire.com/2017/02/25/programming-the-gal22v10/
|
||||
|
||||
- CUPL Reference: http://ee.sharif.edu/~logic_circuits_t/readings/CUPL_Reference.pdf
|
||||
- CUPL Reference: https://web.archive.org/web/20220126145737/https://ee.sharif.edu/~logic_circuits_t/readings/CUPL_Reference.pdf
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
//MCP4151 digital pot (bitbanged control) for Afterburner GAL project.
|
||||
// * compatible with MCP4131 (resolution of the wiper is divided by 2)
|
||||
// * the storage for tap indices is 8bit wide, therefore we must not use index 256.
|
||||
|
||||
// 2024-02-02 Minor change
|
||||
#ifndef __AFTB_MCP4131_H__
|
||||
#define __AFTB_MCP4131_H__
|
||||
|
||||
//set default pins
|
||||
#ifndef POT_CS
|
||||
#define POT_CS A3
|
||||
#endif
|
||||
|
||||
#ifndef POT_CLK
|
||||
#define POT_CLK A4
|
||||
#endif
|
||||
|
||||
#ifndef POT_DAT
|
||||
#define POT_DAT A5
|
||||
#endif
|
||||
|
||||
#ifndef POT_DEFAULT_VALUE
|
||||
#define POT_DEFAULT_VALUE 0x40
|
||||
#endif
|
||||
|
||||
#ifndef POT_WIPER_ENABLED
|
||||
#define POT_WIPER_ENABLED 0
|
||||
#endif
|
||||
|
||||
#define ADDR_WIPER 0
|
||||
#define ADDR_WIPER0 0
|
||||
#define ADDR_WIPER1 1
|
||||
#define ADDR_TCON 4
|
||||
#define ADDR_STAT 5
|
||||
#define ADDR_INCREMENT 100
|
||||
#define CMD_READ (0b11 << 10)
|
||||
#define CMD_INCREMENT (0b01 << 2)
|
||||
|
||||
#define mcp4131_disableWiper() mcp4131_write(ADDR_TCON, 0b111111101)
|
||||
#define mcp4131_enableWiper() mcp4131_write(ADDR_TCON, 0b111111111)
|
||||
#define mcp4131_read(A) mcp4131_reg((A),0,1)
|
||||
#define mcp4131_write(A,V) mcp4131_reg((A),(V),0)
|
||||
|
||||
static uint8_t mcp4131_detected;
|
||||
|
||||
// read or write the mcp4131 register
|
||||
static uint16_t mcp4131_reg(uint8_t address, uint16_t value, uint8_t read_reg) {
|
||||
int8_t i = 15; //16 bit command
|
||||
uint16_t r = address;
|
||||
|
||||
r <<= 12;
|
||||
|
||||
if (mcp4131_detected && address == ADDR_WIPER) {
|
||||
value >>= 1; //divide the wiper value by 2
|
||||
value++; // ensure we use the last tap (index 128)
|
||||
}
|
||||
|
||||
if (address == ADDR_INCREMENT) {
|
||||
r = CMD_INCREMENT;
|
||||
i = 7; // 8 bit command
|
||||
} else
|
||||
if (read_reg) {
|
||||
r |= CMD_READ;
|
||||
} else {
|
||||
r |= value & 0x1FF; // clamp value to 9 bits
|
||||
}
|
||||
|
||||
//setup Clock and and Data (SPI mode 0,0)
|
||||
digitalWrite(POT_CLK, 0);
|
||||
digitalWrite(POT_DAT, 0);
|
||||
delayMicroseconds(50);
|
||||
//activate IC
|
||||
digitalWrite(POT_CS, 0);
|
||||
|
||||
while (i >= 0) {
|
||||
//write address and command (bits 15 to 10)
|
||||
if ((!read_reg) || i > 9) {
|
||||
uint16_t mask = (1 << i);
|
||||
digitalWrite(POT_DAT, (r & mask) ? 1 : 0);
|
||||
}
|
||||
digitalWrite(POT_CLK, 1); //rise the clock
|
||||
//only when reading reg
|
||||
if (read_reg) {
|
||||
//switch the DAT pin to Input
|
||||
if (i == 10) {
|
||||
pinMode(POT_DAT, INPUT);
|
||||
}
|
||||
//read bits 9 to 0
|
||||
if (i < 10) {
|
||||
r |= (digitalRead(POT_DAT) << i); //read after rising edge
|
||||
}
|
||||
}
|
||||
digitalWrite(POT_CLK, 0); //fall the clock
|
||||
i--;
|
||||
}
|
||||
if (read_reg) {
|
||||
pinMode(POT_DAT, OUTPUT);
|
||||
}
|
||||
|
||||
if (mcp4131_detected && address == ADDR_WIPER && read_reg) {
|
||||
r--;
|
||||
r >>= 1; //multiply the wiper value by 2
|
||||
}
|
||||
|
||||
//disable IC
|
||||
digitalWrite(POT_CS, 1);
|
||||
return r & 0x1FF; //clamp value to 9 bits
|
||||
}
|
||||
|
||||
static void mcp4131_init(void) {
|
||||
pinMode(POT_CS, OUTPUT);
|
||||
pinMode(POT_CLK, OUTPUT);
|
||||
pinMode(POT_DAT, OUTPUT);
|
||||
|
||||
digitalWrite(POT_CS, 1); //unselect the POT's SPI bus
|
||||
}
|
||||
|
||||
// initialisation and detection
|
||||
// returns 1 if POT is detected, 0 otherwise
|
||||
static uint8_t mcp4131_detect(void) {
|
||||
uint16_t r;
|
||||
|
||||
mcp4131_detected = 0;
|
||||
|
||||
mcp4131_disableWiper();
|
||||
|
||||
//note checking is done while the wiper is disabled - no resistance is applied
|
||||
mcp4131_write(ADDR_WIPER, 0b1010);
|
||||
r = mcp4131_read(ADDR_WIPER);
|
||||
if (r != 0b1010) {
|
||||
return 0;
|
||||
}
|
||||
mcp4131_write(ADDR_WIPER, 0b101);
|
||||
r = mcp4131_read(ADDR_WIPER);
|
||||
if (r != 0b101) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//sanity check whether the incrementing works
|
||||
mcp4131_write(ADDR_WIPER, 127);
|
||||
mcp4131_write(ADDR_INCREMENT, 0);
|
||||
r = mcp4131_read(ADDR_WIPER);
|
||||
if (r != 128) {
|
||||
return 0;
|
||||
}
|
||||
//detect MCP4151 by incrementing again - MCP4131 clamps the value to 128, MCP4151 increments to 129
|
||||
mcp4131_write(ADDR_INCREMENT, 0);
|
||||
r = mcp4131_read(ADDR_WIPER);
|
||||
#if 0
|
||||
Serial.print(F("MCP4151 detect: "));
|
||||
Serial.println(r == 129 ? 1 : 0, DEC);
|
||||
#endif
|
||||
if (r == 128) {
|
||||
mcp4131_detected = 1;
|
||||
} else
|
||||
if (r != 129) {
|
||||
return 0; //error - the value should be either 128 (clamped by mcp4313) or 129 (mcp5151)
|
||||
}
|
||||
|
||||
mcp4131_write(ADDR_WIPER, POT_DEFAULT_VALUE);
|
||||
#if POT_WIPER_ENABLED
|
||||
mcp4131_enableWiper();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,195 @@
|
|||
#ifndef _AFTB_SERAM_
|
||||
#define _AFTB_SERAM_
|
||||
|
||||
/* Serial RAM functions for Afterburner GAL project.
|
||||
Uses 23LC512 or 23LC1024 RAM IC
|
||||
|
||||
3 devices are connected to the serial bus: digi-pot, shit register and this serial RAM.
|
||||
Digi pot and shift register have their own dedicated CS pins. Serial RAM CS is active (low)
|
||||
when no other device is selected. Therefore, the serial RAM is always selected unless any other
|
||||
device is explicitely selected (in that case serial RAM is de-selected by onboard HW)
|
||||
|
||||
Reading or Writing of 1 byte takes ~ 620 uSec for 24bit addressing and ~ 500 uSec for 16bit addressing
|
||||
|
||||
*/
|
||||
|
||||
//set default pins
|
||||
#ifndef SHR_CS
|
||||
#define SHR_CS A2
|
||||
#endif
|
||||
|
||||
#ifndef RAM_CLK
|
||||
#define RAM_CLK A4
|
||||
#endif
|
||||
|
||||
#ifndef RAM_DAT
|
||||
#define RAM_DAT A5
|
||||
#endif
|
||||
|
||||
#define CS_DELAY_US 16
|
||||
|
||||
#define OPCODE_WRITE 2
|
||||
#define OPCODE_READ 3
|
||||
#define OPCODE_RDMR 5
|
||||
#define OPCODE_WRMR 1
|
||||
|
||||
#ifndef RAM_BIG
|
||||
|
||||
#define seRamInit() 0
|
||||
|
||||
#else /* RAM_BIG */
|
||||
|
||||
uint8_t ramAddrBits24 = 0;
|
||||
|
||||
static void seRamWriteData(uint16_t data, uint8_t bitLen ) {
|
||||
uint16_t mask = (1 << (bitLen-1));
|
||||
|
||||
while (bitLen) {
|
||||
bitLen--;
|
||||
//set data bit
|
||||
digitalWrite(RAM_DAT, (data & mask) ? 1 : 0 );
|
||||
//raise the clock
|
||||
digitalWrite(RAM_CLK, 1);
|
||||
//do some operation
|
||||
data <<= 1;
|
||||
//lower the clock
|
||||
digitalWrite(RAM_CLK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t seRamReadData(void) {
|
||||
uint8_t bitLen = 8;
|
||||
uint8_t result = 0;
|
||||
|
||||
while (bitLen) {
|
||||
result <<= 1;
|
||||
//raise the clock
|
||||
digitalWrite(RAM_CLK, 1);
|
||||
//set data bit
|
||||
result |= digitalRead(RAM_DAT);
|
||||
//do some operation
|
||||
bitLen--;
|
||||
//lower the clock
|
||||
digitalWrite(RAM_CLK, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void seRamWrite(uint16_t addr, uint8_t data ) {
|
||||
//ensure clock is low
|
||||
digitalWrite(RAM_CLK, 0);
|
||||
|
||||
// toggle the SHR CS to reset the bus for serial RAM
|
||||
digitalWrite(SHR_CS, 0);
|
||||
delayMicroseconds(CS_DELAY_US);
|
||||
digitalWrite(SHR_CS, 1);
|
||||
|
||||
seRamWriteData(OPCODE_WRITE, 8); // 8 bits of WRITE opcode
|
||||
if (ramAddrBits24) {
|
||||
seRamWriteData(0, 8); // top 8 bit of address are 0
|
||||
}
|
||||
seRamWriteData(addr, 16); // 16 bits of address
|
||||
seRamWriteData(data, 8); // 8 bits of actual data
|
||||
}
|
||||
|
||||
static uint8_t seRamRead(uint16_t addr) {
|
||||
uint8_t data;
|
||||
//ensure clock is low
|
||||
digitalWrite(RAM_CLK, 0);
|
||||
|
||||
// toggle the SHR CS to reset the bus for serial RAM
|
||||
digitalWrite(SHR_CS, 0);
|
||||
delayMicroseconds(CS_DELAY_US);
|
||||
digitalWrite(SHR_CS, 1);
|
||||
|
||||
seRamWriteData(OPCODE_READ, 8); // 8 bits of READ opcode
|
||||
if (ramAddrBits24) {
|
||||
seRamWriteData(0, 8); // top 8 bit of address are 0
|
||||
}
|
||||
seRamWriteData(addr, 16); // 16 bits of address
|
||||
pinMode(RAM_DAT, INPUT);
|
||||
data = seRamReadData();
|
||||
pinMode(RAM_DAT, OUTPUT);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void seRamSetupMode(void) {
|
||||
uint8_t data;
|
||||
//ensure clock is low
|
||||
digitalWrite(RAM_CLK, 0);
|
||||
|
||||
// toggle the SHR CS to reset the bus for serial RAM
|
||||
digitalWrite(SHR_CS, 0);
|
||||
delayMicroseconds(CS_DELAY_US);
|
||||
digitalWrite(SHR_CS, 1);
|
||||
|
||||
seRamWriteData(OPCODE_RDMR, 8); // 8 bits of Read Mode register
|
||||
pinMode(RAM_DAT, INPUT);
|
||||
data = seRamReadData();
|
||||
pinMode(RAM_DAT, OUTPUT);
|
||||
|
||||
#if 0
|
||||
Serial.print(F("RAM mode:"));
|
||||
Serial.println(data, DEC);
|
||||
#endif
|
||||
|
||||
if (data == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//switch to byte mode
|
||||
// toggle the SHR CS to reset the bus for serial RAM
|
||||
digitalWrite(SHR_CS, 0);
|
||||
delayMicroseconds(CS_DELAY_US);
|
||||
digitalWrite(SHR_CS, 1);
|
||||
seRamWriteData(OPCODE_WRMR, 8); // 8 bits of Read Mode register
|
||||
seRamWriteData(0, 8); //write mode 0
|
||||
|
||||
}
|
||||
|
||||
static uint8_t seRamInit(void) {
|
||||
uint8_t r;
|
||||
|
||||
#if 0
|
||||
pinMode(SHR_CS, OUTPUT);
|
||||
pinMode(RAM_CLK, OUTPUT);
|
||||
pinMode(RAM_DAT, OUTPUT);
|
||||
#endif
|
||||
|
||||
seRamSetupMode();
|
||||
//try 16bit addressing mode (64kb RAM)
|
||||
ramAddrBits24 = 0;
|
||||
|
||||
// detect SRAM presence by writing and reading data
|
||||
seRamWrite(0, 0x5A);
|
||||
r = seRamRead(0);
|
||||
|
||||
#if 0
|
||||
Serial.print("r:");
|
||||
Serial.println(r, DEC);
|
||||
#endif
|
||||
|
||||
|
||||
if (r != 0x5A) {
|
||||
// try 24 bit addressing mode (128kb RAM)
|
||||
ramAddrBits24 = 1;
|
||||
seRamWrite(0, 0x5A);
|
||||
r = seRamRead(0);
|
||||
if (r != 0x5A) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
seRamWrite(0xFFFF, 0xA5);
|
||||
r = seRamRead(0xFFFF);
|
||||
if (r != 0xA5) {
|
||||
return 0;
|
||||
}
|
||||
//verify the data at address 0 still exists
|
||||
r = seRamRead(0);
|
||||
return (r == 0x5A) ? (ramAddrBits24 + 1) : 0;
|
||||
}
|
||||
|
||||
#endif /* RAM_BIG */
|
||||
|
||||
#endif /*_AFTB_SERAM_*/
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Sparse fusemap functions for Afterburner GAL project.
|
||||
*
|
||||
* The idea of sparse fuse map is to store non-zero fuse bits only.
|
||||
* The reason is to fit big fusemaps into a size-limited SRAM.
|
||||
* The fusemap is divided into groups of 16 bits and each group
|
||||
* has a 'type' bit stored in fuseTypes array. Group type 0 has
|
||||
* all 16 fuesmap bits 0 and is not stored in fusemap array.
|
||||
* Group type 1 has at least 1 fusemap bit set and is stored in
|
||||
* fusemap array. Position of group type '1' in the fusemap array
|
||||
* may vary based on which fuses are written.
|
||||
*
|
||||
* Sparse fusemap supports:
|
||||
* - random reads and writes
|
||||
* - a simple cache to speed up index look-ups.
|
||||
*/
|
||||
|
||||
#ifdef USE_SPARSE_FUSEMAP
|
||||
|
||||
// compacting statistics - disabled by default
|
||||
#define COMPACT_STAT 0
|
||||
|
||||
#define SPFUSES 128
|
||||
unsigned char fuseType[SPFUSES]; //sparse fuses index
|
||||
|
||||
uint16_t sparseFusemapStat = 0; //bit 15: use sparse fusemaps, bits 0-11 : sparse fusemap size in bytes
|
||||
uint8_t sparseCompactCounter = 0;
|
||||
uint16_t sparseCacheBitPos = 0;
|
||||
uint16_t sparseCacheOffset = 0;
|
||||
uint16_t sparseCacheHit = 0;
|
||||
uint8_t sparseCacheIndex = 0;
|
||||
|
||||
#if COMPACT_STAT
|
||||
uint8_t sparseCompactRun = 0;
|
||||
uint8_t sparseCompactAct = 0;
|
||||
#endif
|
||||
|
||||
|
||||
// reverse search of the fuse group index based on the byte position in the sparse array
|
||||
// returns the group index
|
||||
static uint16_t getFuseGroupIndex(uint16_t fuseOffsetBytePos) {
|
||||
uint16_t groupPos = 0;
|
||||
uint16_t i = 0;
|
||||
uint16_t fuseOffset = 0;
|
||||
|
||||
//calculate fusemap offset
|
||||
while (1) {
|
||||
uint8_t rec = fuseType[i];
|
||||
// speed optimised special case: all 8 bits are 0 (4 * 32 bits)
|
||||
if (rec == 0) {
|
||||
groupPos += 4; //4 groups in the byte
|
||||
} else {
|
||||
uint8_t j = 0;
|
||||
//4 types per byte
|
||||
while (j < 4) {
|
||||
if ((rec & 0b11) == 1) { // type 0 & 3 - no byte stored in fusemap
|
||||
if (fuseOffset == fuseOffsetBytePos) {
|
||||
return groupPos;
|
||||
}
|
||||
fuseOffset += 4; // 32 bits in the group, fuse byte offset advances by 4 bytes
|
||||
}
|
||||
groupPos++; //check next group
|
||||
rec >>= 2;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
i++; //next byte from the fuseTypes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get position of the fuse bit in the sparse array
|
||||
static uint16_t getFusePositionAndType(uint16_t bitPos) {
|
||||
uint16_t counter = 0;
|
||||
uint8_t i = 0;
|
||||
uint8_t type;
|
||||
uint16_t fuseOffset = (bitPos & 0b11000) >> 3; //set odd / even byte of the fuse offset
|
||||
|
||||
if (bitPos <= sparseCacheBitPos) {
|
||||
sparseCacheBitPos = 0;
|
||||
sparseCacheOffset = 0;
|
||||
sparseCacheIndex = 0;
|
||||
} else {
|
||||
counter = sparseCacheBitPos;
|
||||
fuseOffset += sparseCacheOffset & 0xFFC;
|
||||
i = sparseCacheIndex;
|
||||
sparseCacheHit++;
|
||||
}
|
||||
|
||||
//calculate fusemap offset
|
||||
while (1) {
|
||||
uint8_t rec = fuseType[i];
|
||||
// speed optimised special case: all 8 bits are 0 or all are 1 (4 * 32 bits)
|
||||
if (rec == 0 || rec == 0xFF) {
|
||||
counter += 128;
|
||||
if (counter > bitPos) {
|
||||
return (fuseOffset << 2) | (rec & 0b11); // type is 0 or 3
|
||||
}
|
||||
sparseCacheBitPos = counter;
|
||||
sparseCacheOffset = fuseOffset;
|
||||
sparseCacheIndex = i + 1;
|
||||
}
|
||||
else {
|
||||
uint8_t j = 0;
|
||||
//4 fuse types per byte
|
||||
while (j < 4) {
|
||||
counter += 32;
|
||||
type = rec & 0b11;
|
||||
if (counter > bitPos) {
|
||||
return (fuseOffset << 2) | type;
|
||||
}
|
||||
if (type == 1) { // type 0 & 3 - no byte stored in fusemap
|
||||
fuseOffset += 4;
|
||||
}
|
||||
rec >>= 2;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
i++; //next byte from the fuseTypes
|
||||
}
|
||||
}
|
||||
|
||||
static void insertFuseGroup(uint16_t dataPos, uint16_t bitPos) {
|
||||
int16_t i = bitPos >> 5; //group index
|
||||
uint16_t totalFuseBytes = sparseFusemapStat & 0x7FF; // max is 2048 bytes
|
||||
fuseType[i >> 2] |= (1 << ((i & 0b11) << 1)); // set type 1 at the fuse group record
|
||||
|
||||
//shift all data in the fuse map starting at data pos by 4 bytes (32 bits)
|
||||
if (dataPos < totalFuseBytes) {
|
||||
for (i = totalFuseBytes - 1; i >= dataPos; i--) {
|
||||
fusemap[i + 4] = fusemap[i];
|
||||
}
|
||||
}
|
||||
sparseFusemapStat = totalFuseBytes + 4; // we can ignore the sparse bit
|
||||
//clean the emptied fusemap data
|
||||
fusemap[dataPos++] = 0;
|
||||
fusemap[dataPos++] = 0;
|
||||
fusemap[dataPos++] = 0;
|
||||
fusemap[dataPos] = 0;
|
||||
}
|
||||
|
||||
|
||||
static void sparseCompactFuseMap(void) {
|
||||
uint16_t i, j;
|
||||
uint16_t total = (sparseFusemapStat & 0x7FF) >> 2; // max is 2048 bytes, and convert to the group index
|
||||
uint32_t* fuses = (uint32_t*) fusemap;
|
||||
|
||||
if (total < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if COMPACT_STAT
|
||||
sparseCompactRun++; //statistics
|
||||
#endif
|
||||
|
||||
|
||||
i = total - 1;
|
||||
while(i) {
|
||||
// remove 4 fusemap bytes at a position when the bits are all 1's
|
||||
if (fuses[i] == 0xFFFFFFFF) {
|
||||
if (i < total - 1) {
|
||||
uint16_t fuseGroup = getFuseGroupIndex(i << 2); //ensure the int32 index is converted to int8/byte index
|
||||
#if COMPACT_STAT
|
||||
sparseCompactAct++; //statistics
|
||||
#endif
|
||||
/// shift the fuses by 4 bytes to the left
|
||||
for (j = i; j < total - 1 ; j++) {
|
||||
fuses[j] = fuses[j + 1];
|
||||
}
|
||||
total--;
|
||||
fuseType[fuseGroup >> 2] |= (3 << ((fuseGroup & 0b11) << 1)); //set type 3 at the fuse group record
|
||||
sparseFusemapStat -= 4; // fuse map total size reduced by 4 bytes
|
||||
}
|
||||
}
|
||||
i--;
|
||||
}
|
||||
//destory cache
|
||||
sparseCacheBitPos = 0;
|
||||
sparseCacheOffset = 0;
|
||||
sparseCacheIndex = 0;
|
||||
#if COMPACT_STAT
|
||||
Serial.print(F("sp comp:"));
|
||||
Serial.print(sparseCompactRun, DEC);
|
||||
Serial.print(F(" total:"));
|
||||
Serial.println(sparseFusemapStat & 0x7FF, DEC);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint16_t sparseSetFuseBit(uint16_t bitPos) {
|
||||
uint8_t type;
|
||||
uint16_t pos;
|
||||
|
||||
//try to reduce the size of the fuse map by finding and removing blocks with all 1's
|
||||
sparseCompactCounter ++;
|
||||
if (sparseCompactCounter == 255) {
|
||||
sparseCompactFuseMap();
|
||||
}
|
||||
|
||||
pos = getFusePositionAndType(bitPos);
|
||||
type = pos & 0b11;
|
||||
pos >>= 2; //trim the type to get the byte position in fuse map
|
||||
if (type == 0) { //we need to write the bit into a group that has all bits 0 so far
|
||||
insertFuseGroup(pos & 0x7FC, bitPos);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static inline uint16_t sparseGetFuseBit(uint16_t bitPos) {
|
||||
uint8_t type;
|
||||
uint16_t pos = getFusePositionAndType(bitPos);
|
||||
|
||||
type = pos & 0b11;
|
||||
if (!type) { //type is 0 - the block contains all zero bits
|
||||
return 0xFF00;
|
||||
}
|
||||
if (type == 3) { // type is 3 - the block contains all 1 bits
|
||||
return 0xFF01;
|
||||
}
|
||||
pos >>= 2; //trim the type to get byte position in fuse map
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void sparsePrintStat() {
|
||||
Serial.print(F("sp bytes="));
|
||||
Serial.println(sparseFusemapStat & 0x7FF, DEC);
|
||||
Serial.print(F("c_hit="));
|
||||
Serial.println(sparseCacheHit, DEC);
|
||||
#if COMPACT_STAT
|
||||
Serial.print(F("compact run="));
|
||||
Serial.print(sparseCompactRun, DEC);
|
||||
Serial.print(F(" cnt="));
|
||||
Serial.println(sparseCompactAct, DEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sparseInit(char clearArray) {
|
||||
if (clearArray) {
|
||||
uint8_t i;
|
||||
for (i = 0; i < SPFUSES; i++) {
|
||||
fuseType[i] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
sparseFusemapStat = (1 << 15);
|
||||
sparseCompactCounter = 0;
|
||||
sparseCacheBitPos = 0;
|
||||
sparseCacheOffset = 0;
|
||||
sparseCacheIndex = 0;
|
||||
#if COMPACT_STAT
|
||||
sparseCompactRun = 0;
|
||||
sparseCompactAct = 0;
|
||||
#endif
|
||||
}
|
||||
static inline void sparseDisable(void) {
|
||||
sparseFusemapStat = 0;
|
||||
}
|
||||
#else /* ! USE_SPARSE_FUSEMAP */
|
||||
|
||||
#define sparseDisable()
|
||||
#define sparseInit(X)
|
||||
#define sparseGetFuseBit(X) 0
|
||||
#define sparseSetFuseBit(X) 0
|
||||
#define sparsePrintStat()
|
||||
#define sparseFusemapStat 0
|
||||
#endif
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
* Variable voltage functions for Afterburner GAL project.
|
||||
*
|
||||
* 2024-02-02 Minor changes in varVppInit()
|
||||
*/
|
||||
#ifndef __AFTB_VPP_H__
|
||||
#define __AFTB_VPP_H__
|
||||
|
||||
#include <EEPROM.h>
|
||||
|
||||
// ensure mcp4131 pot uses the right pins
|
||||
#define POT_CS A3
|
||||
#define POT_CLK A4
|
||||
#define POT_DAT A5
|
||||
#define VPP A0
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 == 1
|
||||
// ESP32-S2
|
||||
#include "driver/adc.h"
|
||||
#define ADC_PIN ADC2_CHANNEL_3
|
||||
#define EEPROM_BEGIN() EEPROM.begin(128)
|
||||
#define EEPROM_UPDATE(A,V) if ((V) != EEPROM.read((A))) EEPROM.write((A),(V))
|
||||
#define EEPROM_END() EEPROM.end()
|
||||
#else
|
||||
// AVR
|
||||
#define EEPROM_BEGIN()
|
||||
#define EEPROM_UPDATE(A,V) EEPROM.update((A),(V))
|
||||
#define EEPROM_END()
|
||||
#endif
|
||||
|
||||
#include "aftb_mcp4131.h"
|
||||
#ifndef FAIL
|
||||
#define FAIL 0
|
||||
#define OK 1
|
||||
#endif
|
||||
|
||||
#define ABS(X) ((X) < 0 ? -(X) : (X));
|
||||
#define VPP_5V0 0xFF
|
||||
#define VPP_9V0 0
|
||||
#define VPP_9V5 1
|
||||
#define VPP_10V0 2
|
||||
#define VPP_10V5 3
|
||||
#define VPP_11V0 4
|
||||
#define VPP_11V5 5
|
||||
#define VPP_12V0 6
|
||||
#define VPP_12V5 7
|
||||
#define VPP_13V0 8
|
||||
#define VPP_13V5 9
|
||||
#define VPP_14V0 10
|
||||
#define VPP_14V5 11
|
||||
#define VPP_15V0 12
|
||||
#define VPP_15V5 13
|
||||
#define VPP_16V0 14
|
||||
#define VPP_16V5 15
|
||||
|
||||
#define MAX_WIPER 16
|
||||
|
||||
#define VPP_VERBOSE 0
|
||||
|
||||
#ifdef EXTERNAL
|
||||
#define ANALOG_REF_EXTERNAL EXTERNAL
|
||||
#else
|
||||
#define ANALOG_REF_EXTERNAL AR_EXTERNAL
|
||||
#endif
|
||||
|
||||
//UNO R4 Minima or Wifi (Aref internally pulled down by 130kOhm, AVR Uno R3 pulled down by 32kOhm)
|
||||
#ifdef _RENESAS_RA_
|
||||
#define AREF_IS_3V2
|
||||
#endif
|
||||
|
||||
//pot wiper indices for the voltages
|
||||
uint8_t vppWiper[MAX_WIPER] = {0};
|
||||
|
||||
// VPP must ramp-up to prevent voltage spikes and possibly resetting arduino
|
||||
// These values are for mcp4151 (for mcp4131 they are divided by 2)
|
||||
#define varVppSetMax() varVppSetVppIndex(0x80); \
|
||||
varVppSetVppIndex(0xE0); \
|
||||
varVppSetVppIndex(0xF4); \
|
||||
varVppSetVppIndex(0xFA); \
|
||||
varVppSetVppIndex(0xFF);
|
||||
|
||||
|
||||
#define varVppSetMin() varVppSetVppIndex(0x0);
|
||||
|
||||
uint8_t wiperStat = 0; //enabled / disabled
|
||||
int8_t calOffset = 0; // VPP calibration offset: value 10 is 0.1V, value -10 is -0.1V
|
||||
|
||||
static void varVppReadCalib(void) {
|
||||
uint8_t i;
|
||||
EEPROM_BEGIN();
|
||||
//calibration not found
|
||||
if (EEPROM.read(0) != 0xAF || EEPROM.read(1) != 0xCA) {
|
||||
vppWiper[0] = 0;
|
||||
Serial.println(F("No calibration data in EEPROM"));
|
||||
EEPROM_END();
|
||||
return;
|
||||
}
|
||||
calOffset = (int8_t) EEPROM.read(2);
|
||||
for (i = 0; i < MAX_WIPER; i++) {
|
||||
vppWiper[i] = EEPROM.read(i + 3);
|
||||
#if 0
|
||||
Serial.print(F("Calib "));
|
||||
Serial.print(i);
|
||||
Serial.print(F(":"));
|
||||
Serial.println(vppWiper[i]);
|
||||
#endif
|
||||
}
|
||||
EEPROM_END();
|
||||
}
|
||||
|
||||
// internal use only - set the wiper value on the digital pot
|
||||
static void varVppSetVppIndex(uint8_t value) {
|
||||
uint8_t i;
|
||||
|
||||
#if VPP_VERBOSE
|
||||
Serial.print(F("varSetVppIndex "));
|
||||
Serial.println(value);
|
||||
#endif
|
||||
mcp4131_write(ADDR_WIPER, value);
|
||||
#if VPP_PARANOID
|
||||
i = mcp4131_read(ADDR_WIPER);
|
||||
if (i != value) {
|
||||
Serial.print(F("Error writing POT value. Expected:"));
|
||||
Serial.print(value);
|
||||
Serial.print(F(" Actual:"));
|
||||
Serial.println(i);
|
||||
}
|
||||
#endif
|
||||
if (value == 0) {
|
||||
mcp4131_disableWiper();
|
||||
wiperStat = 0;
|
||||
} else if (wiperStat == 0) {
|
||||
mcp4131_enableWiper();
|
||||
wiperStat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//use by the app code - set the variable voltage
|
||||
static void varVppSet(uint8_t value) {
|
||||
uint8_t v;
|
||||
int8_t inc;
|
||||
if (value == VPP_5V0 || value >= MAX_WIPER) {
|
||||
varVppSetVppIndex(0);
|
||||
return;
|
||||
}
|
||||
#if VPP_VERBOSE
|
||||
Serial.print(F("varSetVpp "));
|
||||
Serial.print(value);
|
||||
Serial.print(F(":"));
|
||||
Serial.println(vppWiper[value]);
|
||||
#endif
|
||||
//ramp up to prevent massive voltage overshoots
|
||||
v = vppWiper[value] / 3;
|
||||
inc = v >> 2;
|
||||
while (v < vppWiper[value]) {
|
||||
varVppSetVppIndex(v);
|
||||
v+= (inc << 1);
|
||||
inc -= (inc >> 1);
|
||||
if (inc < 2) {
|
||||
inc = 2;
|
||||
}
|
||||
}
|
||||
varVppSetVppIndex(vppWiper[value]);
|
||||
}
|
||||
|
||||
// UNO R4/Minima - Renesas IC (significant ADC gain errors measured)
|
||||
#ifdef AREF_IS_3V2
|
||||
#define SAMPLE_CNT 16
|
||||
#define SAMPLE_DIVIDER 8
|
||||
#define SAMPLE_MULTIPLIER 25
|
||||
// SAMPLE_SHIFT moves the ADC gain error up/down
|
||||
#define SAMPLE_SHIFT -45;
|
||||
|
||||
// ESP32-S2 (VREF 2.5V)
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 == 1
|
||||
#define SAMPLE_CNT 18
|
||||
#define SAMPLE_DIVIDER 10
|
||||
#define SAMPLE_MULTIPLIER 1
|
||||
#define SAMPLE_OFFSET 5
|
||||
|
||||
//AVR based Arduinos (no ADC gain errors measured)
|
||||
#else
|
||||
#define SAMPLE_CNT 14
|
||||
#define SAMPLE_DIVIDER 8
|
||||
#define SAMPLE_MULTIPLIER 1
|
||||
#define SAMPLE_OFFSET 5
|
||||
#endif
|
||||
|
||||
static int16_t varVppMeasureVpp(int8_t printValue) {
|
||||
int8_t i = 0;
|
||||
uint16_t r1 = 0;
|
||||
int16_t r2; //correction for ADC gain error
|
||||
|
||||
while (i++ < SAMPLE_CNT) {
|
||||
r1 += analogRead(VPP);
|
||||
}
|
||||
r2 = (r1 / (SAMPLE_DIVIDER * SAMPLE_MULTIPLIER));
|
||||
#ifdef SAMPLE_OFFSET
|
||||
r1+= SAMPLE_OFFSET;
|
||||
#endif
|
||||
r1 /= SAMPLE_DIVIDER;
|
||||
#ifdef SAMPLE_SHIFT
|
||||
r2 += SAMPLE_SHIFT;
|
||||
r1 += r2;
|
||||
#endif
|
||||
r1 += calOffset;
|
||||
if (printValue) {
|
||||
uint8_t a = r1%100;
|
||||
Serial.print(r1/100);
|
||||
Serial.print(F("."));
|
||||
if (a < 10) {
|
||||
Serial.print(F("0"));
|
||||
}
|
||||
#if 1
|
||||
Serial.println(a);
|
||||
#else
|
||||
//debug - display the voltage skew value in r2
|
||||
Serial.print(a);
|
||||
Serial.println(F(", "));
|
||||
Serial.println(r2);
|
||||
#endif
|
||||
}
|
||||
return r1;
|
||||
}
|
||||
|
||||
// Returns 1 on Success, 0 on Failure
|
||||
static uint8_t varVppCalibrateVpp(void) {
|
||||
uint8_t vppIndex = 0;
|
||||
uint8_t i = 1;
|
||||
int16_t v = 900; //starting at 9.00 V
|
||||
int16_t r1 = 0;
|
||||
int16_t r2;
|
||||
int16_t minDif;
|
||||
|
||||
Serial.print(F("VPP calib. offset: "));
|
||||
Serial.println(calOffset);
|
||||
|
||||
varVppSetVppIndex(1);
|
||||
delay(300); //settle voltage
|
||||
|
||||
while (1) {
|
||||
// reset the 'minimal difference' variable every time we search for a new index
|
||||
minDif = 9000;
|
||||
//the 'vppWiper' storage for tap indices is 8bit wide, therefore we must not use tap index 256.
|
||||
while (i <= 0xFF) {
|
||||
int16_t d1,d2;
|
||||
varVppSetVppIndex(i);
|
||||
delay(100); //let the voltage settle
|
||||
|
||||
r2 = varVppMeasureVpp(0);
|
||||
// Sanity check: the previous voltage can't be higher than the voltage just measured
|
||||
// because we are ramping up the voltage. Therefore it must be an ADC measurement
|
||||
// glitch. In that case use the previous value as the measured one.
|
||||
// This can happen at lower tap indices where the voltage differences are very small (like 0.01V).
|
||||
if (r1 > r2) {
|
||||
r2 = r1;
|
||||
}
|
||||
d1 = r1 - v;
|
||||
d2 = r2 - v;
|
||||
d1 = ABS(d1);
|
||||
d2 = ABS(d2);
|
||||
#if VPP_VERBOSE
|
||||
Serial.print(i);
|
||||
Serial.print(F(") r2="));
|
||||
Serial.print(r2, DEC);
|
||||
Serial.print(F(" d1="));
|
||||
Serial.print(d1, DEC);
|
||||
Serial.print(F(" d2="));
|
||||
Serial.print(d2, DEC);
|
||||
Serial.print(F(" md="));
|
||||
Serial.println(minDif, DEC);
|
||||
#endif
|
||||
|
||||
if (r2 <= 100) { // less than 1V ? Failure
|
||||
r1 = FAIL;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if (d2 <= minDif) {
|
||||
minDif = d2;
|
||||
vppWiper[vppIndex] = i;
|
||||
//check last value / voltage
|
||||
if (i == 0xFF) {
|
||||
if (v >= 1620 && v <= 1670) {
|
||||
Serial.println(F("*Index for VPP 1650 is 255"));
|
||||
r1 = OK;
|
||||
goto ret;
|
||||
}
|
||||
r1 = FAIL;
|
||||
goto ret;
|
||||
}
|
||||
} else {
|
||||
i--;
|
||||
minDif = 5000;
|
||||
Serial.print(F("*Index for VPP "));
|
||||
Serial.print(v);
|
||||
Serial.print(F(" is "));
|
||||
Serial.println(i);
|
||||
break;
|
||||
}
|
||||
|
||||
r1 = r2;
|
||||
i++;
|
||||
}
|
||||
vppIndex++;
|
||||
#if VPP_VERBOSE
|
||||
Serial.print(F("vppIndex "));
|
||||
Serial.println(vppIndex);
|
||||
#endif
|
||||
if (vppIndex >= MAX_WIPER) {
|
||||
r1 = OK;
|
||||
goto ret;
|
||||
}
|
||||
v += 50; //next voltage to search for is 0.5V higher
|
||||
}
|
||||
|
||||
ret:
|
||||
varVppSet(VPP_5V0);
|
||||
return r1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void varVppStoreWiperCalib() {
|
||||
uint8_t i = 0;
|
||||
//sanity check
|
||||
if (vppWiper[0] == 0) {
|
||||
#ifdef VPP_VERBOSE
|
||||
Serial.println(F("VPP wiper is 0"));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef VPP_VERBOSE
|
||||
Serial.println(F("VPP storing calibration"));
|
||||
#endif
|
||||
EEPROM_BEGIN();
|
||||
//write Afterburner calibration header
|
||||
EEPROM_UPDATE(0, 0xAF);
|
||||
EEPROM_UPDATE(1, 0xCA);
|
||||
EEPROM_UPDATE(2, (uint8_t) calOffset);
|
||||
while (i < MAX_WIPER) {
|
||||
EEPROM_UPDATE(3 + i, vppWiper[i]);
|
||||
i++;
|
||||
}
|
||||
EEPROM_END();
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 == 1
|
||||
static void analogReference(uint8_t ref) {
|
||||
analogReadResolution(10);
|
||||
adc2_config_channel_atten(ADC_PIN, ADC_ATTEN_DB_11); // AREF 2.5V
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//return 1 on success (variable VPP functionality present), 0 on failure (VPP not detected on board)
|
||||
static int8_t varVppInit(void) {
|
||||
analogReference(ANALOG_REF_EXTERNAL); //use 3V3 external reference
|
||||
analogRead(VPP); // Perform a dummy conversion referring to the datasheet
|
||||
|
||||
wiperStat = 0; //wiper disabled
|
||||
mcp4131_init();
|
||||
if (mcp4131_detect()) {
|
||||
#if VPP_VERBOSE
|
||||
Serial.print(mcp4131_detected ? F("MCP4131") : F("MCP4151"));
|
||||
Serial.println(F(" POT found"));
|
||||
#endif
|
||||
return OK;
|
||||
} else {
|
||||
#if VPP_VERBOSE
|
||||
Serial.println(F("POT not found"));
|
||||
#endif
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
//return 1 on success (VPP calibration appears correct), 0 on failure
|
||||
static int8_t varVppCheckCalibration(void) {
|
||||
int16_t v;
|
||||
|
||||
varVppReadCalib();
|
||||
if (vppWiper[0] == 0) {
|
||||
Serial.println(F("I: VPP not calibrated"));
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// This shoots the VPP to 9V - in theory no GALs should have an issue with that voltage.
|
||||
// Also, the On switch should be turned off, preventing VPP to reach the GAL pins.
|
||||
// check actual voltage
|
||||
varVppSet(VPP_9V0);
|
||||
delay(200); //Settle voltage
|
||||
v = varVppMeasureVpp(0);
|
||||
varVppSet(VPP_5V0); //set VPP back to 5V
|
||||
// lower voltages have a good resolution, so we can have a tight voltage check bounds
|
||||
if (v < 890 || v > 910) {
|
||||
Serial.print(F("ER: VPP voltage check of 9V failed. Expected 900, measured "));
|
||||
Serial.println(v);
|
||||
return FAIL;
|
||||
}
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
// only for VPP testing and debugging
|
||||
static void varrVppTestRamp(void) {
|
||||
uint8_t i = 1;
|
||||
|
||||
while (i < 256) {
|
||||
varVppSetVppIndex(i);
|
||||
delay(400);
|
||||
Serial.println(i, DEC);
|
||||
varVppMeasureVpp(1);
|
||||
i++;
|
||||
}
|
||||
delay(2000);
|
||||
varVppSetVppIndex(0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int8_t varVppCalibrate(void) {
|
||||
#if 0
|
||||
// only for testing and debugging
|
||||
varrVppTestRamp();
|
||||
return OK;
|
||||
#endif
|
||||
|
||||
if (varVppCalibrateVpp()) {
|
||||
varVppStoreWiperCalib();
|
||||
} else {
|
||||
Serial.println(F("ER: Wiper calibration failed"));
|
||||
return FAIL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
#endif
|
2016
afterburner.ino
69
bom.txt
|
@ -1,35 +1,54 @@
|
|||
BOM for Afterburner 1.3
|
||||
========================
|
||||
* Resistor 4k7 through hole 0.25W, 5% or better tolerance - 7x
|
||||
* (R4) Resistor 10k through hole 0.25W, 5% or better tolrance - 1x
|
||||
* Capacitor electrolytic 10uF, 20V to 35 V, 20% tolerance or better (through hole) - 1x
|
||||
* Capacitor ceramic 100nF (through hole or smt) - 1x
|
||||
* 20 pin narrow ZIF socket OR 20 pin DIP IC socket 2.56 mm pin spacing - 1x
|
||||
* 5mm LED (through hole) - 1x
|
||||
* MT3608 module - 1x
|
||||
* 2 Position 4mm SPDT 1P2T 3 Pin PCB Panel Vertical Slide Switch (0.1" pin spacing) - 1x
|
||||
* 40 Pin Male Single Row Strip 2.54mm Pin Header Connector 0.1" Straight - 1x
|
||||
* Arduino UNO
|
||||
BOM for Afterburner PCB 3.2b
|
||||
============================
|
||||
* (R1 - 5x) Resistor 4k7 (TH or SMT 0805) 0.25W, 5% or better tolerance - 5x
|
||||
* (R8, R4) Resistor 10k (TH or SMT 0805) 1% or better tolerance - 2x
|
||||
* (R5, R18) Resistor 100k (TH or SMT 0805) 1% or better tolerance - 2x
|
||||
* (R6) Resistor 20k (TH or SMT 0805) 1% or better tolerance - 1x
|
||||
* (R7, R3, R2) Resistor 3k3 (TH or SMT 0805) 1% or better tolerance - 3x
|
||||
* (R9) Cermet trimmer (TH Suntan TSR-3362P-202R 2k) - 1x
|
||||
|
||||
*Optionally : Mini Size Led Panel Voltage Meter 3-Digital Lcd Display - 1x
|
||||
* (C1, C5) Capacitor electrolytic 10uF, 25V or 50V, 20% tolerance or better (through hole) - 2x
|
||||
* (C4) Capacitor electrolytic 220uF, 16V or higher, 20% tolerance or better (through hole) - 1x
|
||||
* (C2, C3, C8, C9) Capacitor ceramic 100nF 10V or higher (TH or SMT 0805) - 4x
|
||||
* (C6) Capacitor ceramic 100nF 25V or higher (TH or SMT 0805) - 1x
|
||||
* (C7) Capacitor ceramic 2nF 25V or higher (TH or SMT 0805) - 1x
|
||||
|
||||
* (D1) 5mm LED (TH or SMT 0805) - 1x
|
||||
* (Q1) N-MOSFET (SMT: BSS138P - SOT23 or TH: BS170G - TO92, or similar) - 1x
|
||||
|
||||
* (U1) MCP4131-103 (DIP or SOIC) Digital potentiometer 10k - 1x
|
||||
Alternatively MCP4151-103 can be used as well.
|
||||
* (U2) 74HC595 (DIP or SOIC) Shift register - 1x
|
||||
|
||||
BOM for Afterburner 2.2
|
||||
=======================
|
||||
* Resistor 4k7 through hole 0.25W, 5% or better tolerance - 12x
|
||||
* (R4) Resistor 10k through hole 0.25W, 5% or better tolrance - 1x
|
||||
* Capacitor electrolytic 10uF, 20V to 35V, 20% tolerance or better (through hole) - 1x
|
||||
* Capacitor ceramic 100nF (through hole or smt) - 2x
|
||||
* 20 pin narrow ZIF socket OR 20 pin DIP IC socket 0.1" pin spacing - 1x
|
||||
* 24 pin narrow ZIF socket OR 24 pin DIP IC socket 0.1" pin spacing - 1x
|
||||
* 5mm LED (through hole) - 1x
|
||||
* MT3608 module - 1x
|
||||
* 2 Position 4mm SPDT 1P2T 3 Pin PCB Panel Vertical Slide Switch (0.1" pin spacing) - 1x
|
||||
* Square 7x7x12mm 6 Pin DPDT Mini Push Button Self-locking Multimeter Switch (YTSPS-22E70L, 2mm pin spacing) - 1x
|
||||
* 40 Pin Male Single Row Strip 2.54mm Pin Header Connector 0.1" Straight - 1x
|
||||
* Arduino UNO
|
||||
|
||||
*Optionally : Mini Size Led Panel Voltage Meter 3-Digital Lcd Display - 1x
|
||||
|
||||
|
||||
|
||||
OPTIONAL features
|
||||
-----------------
|
||||
on-board voltage booster (replacement for MT3608 module)
|
||||
|
||||
* (R10, R13 ,R14) Resistor 100k (TH or SMT 0805) 1% or better tolerance - 3x
|
||||
* (R11) Resistor 4k7 (TH or SMT 0805) 0.25W, 1% or better tolerance - 1x
|
||||
* (R12) Resistor 3k3 (TH or SMT 0805) 1% or better tolerance - 1x
|
||||
* (C10) Capacitor ceramic 1uF, 9V or higher (TH or SMT 0805) - 1x
|
||||
* (D2) Diode Schottky SK14, 1A 40V (SMT package DO-214AC-2 )
|
||||
or alternative TH Schottky diode 1N5818
|
||||
* (L1) Inductor 10uH, NLCV32T-100K-PF (SMT package 1210)
|
||||
or alternative TH: AICC-02-100K-T Axial inductor
|
||||
* (U3) Voltage booster MIC2619 (SOT-23-6) with over voltage protection (OVP)
|
||||
or alternative MIC2250 (SOT-23-5) without OVP, R10, R11 and R12 not required
|
||||
or possibly TPS61040DBVR (SOT-23-5) without OVP - not tested yet
|
||||
|
||||
SPI-RAM: extra memory for UNO (not used ATM. Can be soldered later if needed)
|
||||
|
||||
* (R15, R16) Resistor 10k (TH or SMT 0805) 5% or better tolerance - 2x
|
||||
* (R17) Resistor 4k7 (TH or SMT 0805) 0.25W, 5% or better tolerance - 1x
|
||||
* (C11) Capacitor ceramic 100nF 10V or higher (TH or SMT 0805) - 1x
|
||||
* (Q2,Q3) N-MOSFET (SMT: BSS138P - SOT23 or TH: BS170G - TO92, or similar) - 2x
|
||||
* (U4) SPI-RAM 5V, 23LC1024, DIP or SOIC-8, alternative 23LC512 or 23LCV512 or 23LCV1024
|
||||
|
||||
|
||||
|
|
313
case/aft1x.scad
|
@ -1,313 +0,0 @@
|
|||
//############################################################
|
||||
// Afterburner 1.X case (ver. 2)
|
||||
//############################################################
|
||||
|
||||
//Rendering details
|
||||
details = 60; // [60:Preview-Quick, 360:Export-Slow]
|
||||
|
||||
//Export Top case
|
||||
enableTop = true;
|
||||
|
||||
//Export Bottom case
|
||||
enableBottom = true;
|
||||
|
||||
//Export power switch
|
||||
enablePowerSwitch = true;
|
||||
|
||||
//Disaply Arduino
|
||||
enableArduino = true;
|
||||
|
||||
//Draw text logo
|
||||
enableTexts = true;
|
||||
|
||||
//Distance between the top and the bottom case
|
||||
caseDistance = 32; //[32:200]
|
||||
|
||||
//Overall Case scale - options for print services
|
||||
caseScale = 1000; // [1000: 100% Exact printer, 996: 99.6% JLCPCB]
|
||||
|
||||
//################################################################
|
||||
module __Customizer_Limit__ () {}
|
||||
$fn = details;
|
||||
|
||||
//Arduino model
|
||||
include <arduino.scad>
|
||||
|
||||
|
||||
// Case edge radius
|
||||
edgeR = 2;
|
||||
|
||||
// Case Wall thickness
|
||||
wallT = 2;
|
||||
|
||||
// space for the case mounting holes
|
||||
spaceD = 8;
|
||||
|
||||
caseW = 76;
|
||||
caseD = 58 + (2 * spaceD); //58
|
||||
caseH = 2;
|
||||
|
||||
|
||||
module outline(wall = 1) {
|
||||
difference() {
|
||||
offset( 0) children();
|
||||
offset(-wall) children();
|
||||
}
|
||||
}
|
||||
|
||||
// Afterburner shield
|
||||
module afterburner() {
|
||||
pcbHeight = 1.6;
|
||||
linear_extrude(pcbHeight) square([54, 55.4]);
|
||||
//place components
|
||||
translate([0,0, pcbHeight]) {
|
||||
// Ziff socket
|
||||
translate([5.3, 15.6, 0]) linear_extrude(12) square([15, 41]);
|
||||
|
||||
// On/Off switch
|
||||
translate([25.7, 36.3, 0]) linear_extrude(5) square([4, 8.7]);
|
||||
// On/Off switch lever
|
||||
translate([26.7, 38.6, 5]) linear_extrude(6) square([2, 4]);
|
||||
|
||||
//LED
|
||||
translate([24.2, 18.5, 0]) linear_extrude(4) circle(2);
|
||||
|
||||
|
||||
// VPP supply - pcb
|
||||
translate([30.5, 13.5, 3.3]) linear_extrude(1.2) square([17.4, 37.2]);
|
||||
// VPP supply - trimmer
|
||||
translate([35.5, 21, 3.3 + 1.2]) linear_extrude(5) square([10, 9.5]);
|
||||
// VPP supply - trimmer knob
|
||||
translate([45.5, 22.2, 3.3 + 1.2 + 3.3]) rotate([0,90,0]) linear_extrude(2) circle(1.2);
|
||||
|
||||
// screwdriver shaft
|
||||
translate([48.5, 22.2, 3.3 + 1.2 + 3.3]) rotate([0,90,0]) linear_extrude(35 + spaceD) circle(1.2);
|
||||
|
||||
//VPP measurement header
|
||||
translate([25.8, 11.5, 0]) linear_extrude(12.2) square([2.7, 5.4]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module nutHolder() {
|
||||
size = spaceD + 1;
|
||||
center = size / 2;
|
||||
difference() {
|
||||
// main box
|
||||
linear_extrude(height = 7.5) square([size, size]);
|
||||
// holes
|
||||
{
|
||||
//central hole
|
||||
translate([center, center, -0.01]) linear_extrude(height = 10.5) circle(2.5);
|
||||
//retention dip 1
|
||||
translate([center - 1, center - (center/2) - 1.2, 1.5]) linear_extrude(height = 3.5) square([2.4, 6.5]);
|
||||
//retention dip 2
|
||||
translate([center - (center/2) - 1, center - 1.2, 2.0]) linear_extrude(height = 3.4) square([6.5, 2.4]);
|
||||
}
|
||||
}
|
||||
// M3 screw mockup
|
||||
%translate([center, center, -12]) linear_extrude(height = 16) circle(1.3);
|
||||
|
||||
}
|
||||
|
||||
module caseTop() {
|
||||
wall2H = 0;
|
||||
wallH = 22.0;
|
||||
skirtT = 1.8; //skirt thickness
|
||||
skirt1 = [0.3, 0.3, 0.9]; //blue
|
||||
skirt2 = [0.3, 0.8, 0.9]; //cyan
|
||||
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
// base shape
|
||||
translate([0,0,0]) linear_extrude(height = caseH) offset(edgeR) square([caseW, caseD]);
|
||||
|
||||
//base wall
|
||||
translate([0,0,-wallH]) {
|
||||
linear_extrude(wallH) {
|
||||
outline(wallT) offset(edgeR) square([caseW, caseD]);
|
||||
}
|
||||
|
||||
//wall skirt small and closer to wall
|
||||
color (skirt1) translate([0,0, -wall2H + 0.001]) {
|
||||
linear_extrude(2) {
|
||||
outline(wallT) offset(edgeR-0.5) square([caseW-0.5, caseD-0.5]);
|
||||
}
|
||||
}
|
||||
color (skirt2) translate([0.25, 0.25, -wall2H -2]) {
|
||||
linear_extrude(3.5) {
|
||||
outline(skirtT) offset(edgeR - wallT - 0.1) square([caseW-0.5, caseD-0.5]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// case mounting holes with nuts
|
||||
translate([0,0, -wallH]) {
|
||||
holderSize = spaceD + 1;
|
||||
nutHolder();
|
||||
translate([caseW - holderSize, 0, 0]) nutHolder();
|
||||
translate([0, caseD - holderSize, 0]) nutHolder();
|
||||
translate([caseW - holderSize, caseD - holderSize, 0]) nutHolder();
|
||||
}
|
||||
|
||||
translate([0, spaceD ,0]) {
|
||||
//ziff lever box (+)
|
||||
translate([74, 42, -9]) linear_extrude(height = 10) square([3, 12]);
|
||||
|
||||
//ziff skirt
|
||||
translate([31, 33,-4.5]) linear_extrude(height = 6) square([44.5, 20.5]);
|
||||
|
||||
// VPP trimmer access box (+)
|
||||
translate([30.5, -1 - spaceD, -7]) linear_extrude(height = 9) square([18, 6 + spaceD]);
|
||||
|
||||
// LED hole retention (bottom side)
|
||||
translate([37.25, 25.8, -2]) linear_extrude(height = 2.3) square([6,6]);
|
||||
|
||||
}
|
||||
}
|
||||
// case cut-throughs
|
||||
{
|
||||
translate([0, spaceD ,0]) {
|
||||
// USB socket hole
|
||||
translate([-3, 34,-wallH - 3.7]) linear_extrude(height = 15.5) square([6, 14]);
|
||||
|
||||
// Power jack hole
|
||||
translate([-3, 5.6,-wallH - 3.7]) linear_extrude(height = 15.5) square([6.01, 10]);
|
||||
|
||||
// texts
|
||||
if (enableTexts) {
|
||||
translate([0, -spaceD + caseD / 2, -0.79]) {
|
||||
translate([caseW / 2, -19, caseH]) scale([1,1.2,1]) linear_extrude(height=1) text("Afterburner", size=7.5, font="Liberation Mono:style=Bold Italic", halign="center");
|
||||
translate([70, -3.0, caseH]) linear_extrude(height=1.3) text("ON", size=5, font="DejaVu Sans Mono:style=Bold", halign="center");
|
||||
}
|
||||
}
|
||||
|
||||
union() {
|
||||
// Ziff socket hole
|
||||
translate([33,35,-9.5]) linear_extrude(height = 12) square([42, 16.5]);
|
||||
|
||||
//ziff lever box (-)
|
||||
translate([69, 45.5, -7]) linear_extrude(height = 10) square([9.1, 6]);
|
||||
|
||||
// VPP trimmer access box (-)
|
||||
translate([34.5, -13, -5]) linear_extrude(height = 9) offset(2) square([10, 6 + spaceD]);
|
||||
|
||||
// VPP trimmer access box hole
|
||||
translate([39.9, 11, -2]) rotate([90,0,0]) linear_extrude(height = 10) circle(2);
|
||||
|
||||
//LED hole - use light pipe
|
||||
//translate([35.6, 31.5, 1.01]) linear_extrude(height = 1) circle(2);
|
||||
//translate([40, 29, 1.01]) linear_extrude(height = 1) circle(2);
|
||||
translate([40, 29, -2.1]) linear_extrude(height = 5) circle(1.7);
|
||||
|
||||
//Power switch hole
|
||||
translate([53.2, 25.7, -5]) linear_extrude(height = 10) square([9.5, 5]);
|
||||
|
||||
//VPP measurement header hole
|
||||
translate([29.8, 28.0, -5]) linear_extrude(height = 10) offset(1) square([4.2, 1.7]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module antislipperyRing() {
|
||||
translate([0,0,-2.7])linear_extrude(2.7) outline(1) circle(7.3);
|
||||
% translate([0,0,-4.02]) linear_extrude(4) circle(6.1);
|
||||
}
|
||||
|
||||
module caseBottom() {
|
||||
wallH = 7.5;
|
||||
holderSize = spaceD + 1;
|
||||
center = holderSize / 2;
|
||||
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
// base shape
|
||||
translate([0,0,0]) linear_extrude(height = caseH) offset(edgeR) square([caseW, caseD]);
|
||||
|
||||
//base wall
|
||||
translate([0,0,caseH]) {
|
||||
linear_extrude(wallH) {
|
||||
outline(wallT) offset(edgeR) square([caseW, caseD]);
|
||||
}
|
||||
}
|
||||
translate([2.2,56 + spaceD,1]) rotate([0, 0, -90]) {
|
||||
//Arduino standoffs
|
||||
standoffs(height = 7, holeRadius = 1.35, bottomRadius = 4, topRadius = 3.5);
|
||||
//top-left standoff rod
|
||||
translate([2.4, 15.2, 0]) linear_extrude(9) circle(1.4);
|
||||
//place Arduino UNO on top of the standoffs
|
||||
if (enableArduino) {
|
||||
% translate([0,0,7.01]) {
|
||||
arduino(boardType = UNO, useColors = false);
|
||||
translate([0,15.5, 12.6]) afterburner();
|
||||
}
|
||||
}
|
||||
}
|
||||
// mounting holes extra wall
|
||||
{
|
||||
translate([center, center, 0.95]) linear_extrude(height = 3) circle(5); //top thick
|
||||
translate([center + caseW - holderSize, center, 0.95]) linear_extrude(height = 3) circle(5);
|
||||
translate([center, center + caseD - holderSize, 0.95]) linear_extrude(height = 3) circle(5);
|
||||
translate([center + caseW - holderSize, center + caseD - holderSize, 0.95]) linear_extrude(height = 3) circle(5);
|
||||
|
||||
}
|
||||
//anti-slippery rings
|
||||
{
|
||||
centerR = 14;
|
||||
translate([centerR, centerR]) antislipperyRing();
|
||||
translate([caseW - centerR, centerR]) antislipperyRing();
|
||||
translate([centerR, caseD - centerR]) antislipperyRing();
|
||||
translate([caseW - centerR, caseD - centerR]) antislipperyRing();
|
||||
}
|
||||
}
|
||||
//mounting holes
|
||||
{
|
||||
// case mounting holes
|
||||
translate([center, center, -2]) {
|
||||
linear_extrude(height = 6) circle(1.7);
|
||||
linear_extrude(height = 4.3) circle(3.5); //recess
|
||||
}
|
||||
|
||||
translate([center + caseW - holderSize, center, -2]) {
|
||||
linear_extrude(height = 6) circle(1.7);
|
||||
linear_extrude(height = 4.3) circle(3.5); //recess
|
||||
}
|
||||
|
||||
translate([center, center + caseD - holderSize, -2]) {
|
||||
linear_extrude(height = 6) circle(1.7);
|
||||
linear_extrude(height = 4.3) circle(3.5); //recess
|
||||
}
|
||||
|
||||
translate([center + caseW - holderSize, center + caseD - holderSize, -2]) {
|
||||
linear_extrude(height = 6) circle(1.7);
|
||||
linear_extrude(height = 4.3) circle(3.5); //recess
|
||||
}
|
||||
|
||||
// top left post - dips for soldered pins
|
||||
translate([17.4, 58, 5]) linear_extrude(height=6) circle(1);
|
||||
translate([20.8, 61.5, 5]) linear_extrude(height=6) circle(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module powerSwitch() {
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(4.5) square([18,6]);
|
||||
translate([7.5, 1.6])linear_extrude(10) offset(1) square([3, 2.4]);
|
||||
}
|
||||
translate([8.15, 2.15, -0.01])linear_extrude(5.2) square([1.7, 1.7]);
|
||||
}
|
||||
}
|
||||
// allows to fine-tune the overall size before export
|
||||
worldScale = caseScale / 1000;
|
||||
|
||||
scale(worldScale) {
|
||||
if (enableBottom) caseBottom();
|
||||
if (enableTop) translate([0,0, caseDistance + 0.2]) caseTop();
|
||||
if (enablePowerSwitch) translate([47, spaceD + 25.4, caseDistance - 4.6]) powerSwitch();
|
||||
}
|
|
@ -1,473 +0,0 @@
|
|||
// Arduino connectors library
|
||||
//
|
||||
// Copyright (c) 2013 Kelly Egan
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
// and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
// portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// https://github.com/kellyegan/OpenSCAD-Arduino-Mounting-Library
|
||||
|
||||
//use <pin_connectors/pins.scad>
|
||||
|
||||
//Constructs a roughed out arduino board
|
||||
//Current only USB, power and headers
|
||||
module arduino(boardType = UNO, useColors = true) {
|
||||
//The PCB with holes
|
||||
if (useColors) difference() {
|
||||
color("SteelBlue") boardShape( boardType );
|
||||
translate([0,0,-pcbHeight * 0.5]) holePlacement(boardType = boardType)
|
||||
color("SteelBlue") cylinder(r = mountingHoleRadius, h = pcbHeight * 2, $fn=32);
|
||||
} else difference() {
|
||||
boardShape( boardType );
|
||||
translate([0,0,-pcbHeight * 0.5]) holePlacement(boardType = boardType)
|
||||
cylinder(r = mountingHoleRadius, h = pcbHeight * 2, $fn=32);
|
||||
}
|
||||
|
||||
//Add all components to board
|
||||
components( boardType = boardType, component = ALL, useColors = useColors );
|
||||
}
|
||||
|
||||
|
||||
//Setting for enclosure mounting holes (Not Arduino mounting)
|
||||
NOMOUNTINGHOLES = 0;
|
||||
INTERIORMOUNTINGHOLES = 1;
|
||||
EXTERIORMOUNTINGHOLES = 2;
|
||||
|
||||
|
||||
//Offset from board. Negative values are insets
|
||||
module boardShape( boardType = UNO, offset = 0, height = pcbHeight ) {
|
||||
dimensions = boardDimensions(boardType);
|
||||
|
||||
xScale = (dimensions[0] + offset * 2) / dimensions[0];
|
||||
yScale = (dimensions[1] + offset * 2) / dimensions[1];
|
||||
|
||||
translate([-offset, -offset, 0])
|
||||
scale([xScale, yScale, 1.0])
|
||||
linear_extrude(height = height)
|
||||
polygon(points = boardShapes[boardType]);
|
||||
}
|
||||
|
||||
//Create a bounding box around the board
|
||||
//Offset - will increase the size of the box on each side,
|
||||
//Height - overides the boardHeight and offset in the z direction
|
||||
|
||||
BOARD = 0; //Includes all components and PCB
|
||||
PCB = 1; //Just the PCB
|
||||
COMPONENTS = 2; //Just the components
|
||||
|
||||
module boundingBox(boardType = UNO, offset = 0, height = 0, cornerRadius = 0, include = BOARD) {
|
||||
//What parts are included? Entire board, pcb or just components.
|
||||
pos = ([boardPosition(boardType), pcbPosition(boardType), componentsPosition(boardType)])[include];
|
||||
dim = ([boardDimensions(boardType), pcbDimensions(boardType), componentsDimensions(boardType)])[include];
|
||||
|
||||
//Depending on if height is set position and dimensions will change
|
||||
position = [
|
||||
pos[0] - offset,
|
||||
pos[1] - offset,
|
||||
(height == 0 ? pos[2] - offset : pos[2] )
|
||||
];
|
||||
|
||||
dimensions = [
|
||||
dim[0] + offset * 2,
|
||||
dim[1] + offset * 2,
|
||||
(height == 0 ? dim[2] + offset * 2 : height)
|
||||
];
|
||||
|
||||
translate( position ) {
|
||||
if( cornerRadius == 0 ) {
|
||||
cube( dimensions );
|
||||
} else {
|
||||
roundedCube( dimensions, cornerRadius=cornerRadius );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Creates standoffs for different boards
|
||||
TAPHOLE = 0;
|
||||
PIN = 1;
|
||||
|
||||
module standoffs(
|
||||
boardType = UNO,
|
||||
height = 10,
|
||||
topRadius = mountingHoleRadius + 1,
|
||||
bottomRadius = mountingHoleRadius + 2,
|
||||
holeRadius = mountingHoleRadius,
|
||||
mountType = TAPHOLE
|
||||
) {
|
||||
|
||||
holePlacement(boardType = boardType)
|
||||
union() {
|
||||
difference() {
|
||||
cylinder(r1 = bottomRadius, r2 = topRadius, h = height, $fn=32);
|
||||
if( mountType == TAPHOLE ) {
|
||||
cylinder(r = holeRadius, h = height * 4, center = true, $fn=32);
|
||||
}
|
||||
}
|
||||
if( mountType == PIN ) {
|
||||
translate([0, 0, height - 1])
|
||||
pintack( h=pcbHeight + 3, r = holeRadius, lh=3, lt=1, bh=1, br=topRadius );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This is used for placing the mounting holes and for making standoffs
|
||||
//child elements will be centered on that chosen boards mounting hole centers
|
||||
module holePlacement(boardType = UNO ) {
|
||||
for(i = boardHoles[boardType] ) {
|
||||
translate(i)
|
||||
children(0);
|
||||
}
|
||||
}
|
||||
|
||||
//Places components on board
|
||||
// compenent - the data set with a particular component (like boardHeaders)
|
||||
// extend - the amount to extend the component in the direction of its socket
|
||||
// offset - the amount to increase the components other two boundaries
|
||||
|
||||
//Component IDs
|
||||
ALL = -1;
|
||||
HEADER_F = 0;
|
||||
HEADER_M = 1;
|
||||
USB = 2;
|
||||
POWER = 3;
|
||||
RJ45 = 4;
|
||||
|
||||
module components( boardType = UNO, component = ALL, extension = 0, offset = 0, useColors = false ) {
|
||||
translate([0, 0, pcbHeight]) {
|
||||
for( i = [0:len(components[boardType]) - 1] ){
|
||||
if( components[boardType][i][3] == component || component == ALL) {
|
||||
//Calculates position + adjustment for offset and extention
|
||||
position = components[boardType][i][0]
|
||||
- (([1,1,1] - components[boardType][i][2]) * offset)
|
||||
+ [ min(components[boardType][i][2][0],0), min(components[boardType][i][2][1],0), min(components[boardType][i][2][2],0) ]
|
||||
* extension;
|
||||
//Calculates the full box size including offset and extention
|
||||
dimensions = components[boardType][i][1]
|
||||
+ ((components[boardType][i][2] * [1,1,1])
|
||||
* components[boardType][i][2]) * extension
|
||||
+ ([1,1,1] - components[boardType][i][2]) * offset * 2;
|
||||
translate( position ) {
|
||||
if (useColors) color( components[boardType][i][4] ) cube( dimensions );
|
||||
if (!useColors) cube( dimensions );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module roundedCube( dimensions = [10,10,10], cornerRadius = 1, faces=32 ) {
|
||||
hull() cornerCylinders( dimensions = dimensions, cornerRadius = cornerRadius, faces=faces );
|
||||
}
|
||||
|
||||
module cornerCylinders( dimensions = [10,10,10], cornerRadius = 1, faces=32 ) {
|
||||
translate([ cornerRadius, cornerRadius, 0]) {
|
||||
cylinder( r = cornerRadius, $fn = faces, h = dimensions[2] );
|
||||
translate([dimensions[0] - cornerRadius * 2, 0, 0]) cylinder( r = cornerRadius, $fn = faces, h = dimensions[2] );
|
||||
translate([0, dimensions[1] - cornerRadius * 2, 0]) {
|
||||
cylinder( r = cornerRadius, $fn = faces, h = dimensions[2] );
|
||||
translate([dimensions[0] - cornerRadius * 2, 0, 0]) cylinder( r = cornerRadius, $fn = faces, h = dimensions[2] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Create a clip that snapps into a clipHole
|
||||
module clip(clipWidth = 5, clipDepth = 5, clipHeight = 5, lipDepth = 1.5, lipHeight = 3) {
|
||||
translate([-clipWidth/2,-(clipDepth-lipDepth),0]) rotate([90, 0, 90])
|
||||
linear_extrude(height = clipWidth, convexity = 10)
|
||||
polygon( points=[ [0, 0],
|
||||
[clipDepth - lipDepth, 0],
|
||||
[clipDepth - lipDepth, clipHeight - lipHeight],
|
||||
[clipDepth - 0.25, clipHeight - lipHeight],
|
||||
[clipDepth, clipHeight - lipHeight + 0.25],
|
||||
[clipDepth - lipDepth * 0.8, clipHeight],
|
||||
[(clipDepth - lipDepth) * 0.3, clipHeight]
|
||||
],
|
||||
paths=[[0,1,2,3,4,5,6,7]]
|
||||
);
|
||||
}
|
||||
|
||||
//Hole for clip
|
||||
module clipHole(clipWidth = 5, clipDepth = 5, clipHeight = 5, lipDepth = 1.5, lipHeight = 3, holeDepth = 5) {
|
||||
offset = 0.1;
|
||||
translate([-clipWidth/2,-(clipDepth-lipDepth),0])
|
||||
translate([-offset, clipDepth - lipDepth-offset, clipHeight - lipHeight - offset])
|
||||
cube( [clipWidth + offset * 2, holeDepth, lipHeight + offset * 2] );
|
||||
}
|
||||
|
||||
module mountingHole(screwHeadRad = woodscrewHeadRad, screwThreadRad = woodscrewThreadRad, screwHeadHeight = woodscrewHeadHeight, holeDepth = 10) {
|
||||
union() {
|
||||
translate([0, 0, -0.01])
|
||||
cylinder( r = screwThreadRad, h = 1.02, $fn = 32 );
|
||||
translate([0, 0, 1])
|
||||
cylinder( r1 = screwThreadRad, r2 = screwHeadRad, h = screwHeadHeight, $fn = 32 );
|
||||
translate([0, 0, screwHeadHeight - 0.01 + 1])
|
||||
cylinder( r = screwHeadRad, h = holeDepth - screwHeadHeight + 0.02, $fn = 32 );
|
||||
}
|
||||
}
|
||||
|
||||
/******************************** UTILITY FUNCTIONS *******************************/
|
||||
|
||||
//Return the length side of a square given its diagonal
|
||||
function sides( diagonal ) = sqrt(diagonal * diagonal / 2);
|
||||
|
||||
//Return the minimum values between two vectors of either length 2 or 3. 2D Vectors are treated as 3D vectors who final value is 0.
|
||||
function minVec( vector1, vector2 ) =
|
||||
[min(vector1[0], vector2[0]), min(vector1[1], vector2[1]), min((vector1[2] == undef ? 0 : vector1[2]), (vector2[2] == undef ? 0 : vector2[2]) )];
|
||||
|
||||
//Return the maximum values between two vectors of either length 2 or 3. 2D Vectors are treated as 3D vectors who final value is 0.
|
||||
function maxVec( vector1, vector2 ) =
|
||||
[max(vector1[0], vector2[0]), max(vector1[1], vector2[1]), max((vector1[2] == undef ? 0 : vector1[2]), (vector2[2] == undef ? 0 : vector2[2]) )];
|
||||
|
||||
//Determine the minimum point on a component in a list of components
|
||||
function minCompPoint( list, index = 0, minimum = [10000000, 10000000, 10000000] ) =
|
||||
index >= len(list) ? minimum : minCompPoint( list, index + 1, minVec( minimum, list[index][0] ));
|
||||
|
||||
//Determine the maximum point on a component in a list of components
|
||||
function maxCompPoint( list, index = 0, maximum = [-10000000, -10000000, -10000000] ) =
|
||||
index >= len(list) ? maximum : maxCompPoint( list, index + 1, maxVec( maximum, list[index][0] + list[index][1]));
|
||||
|
||||
//Determine the minimum point in a list of points
|
||||
function minPoint( list, index = 0, minimum = [10000000, 10000000, 10000000] ) =
|
||||
index >= len(list) ? minimum : minPoint( list, index + 1, minVec( minimum, list[index] ));
|
||||
|
||||
//Determine the maximum point in a list of points
|
||||
function maxPoint( list, index = 0, maximum = [-10000000, -10000000, -10000000] ) =
|
||||
index >= len(list) ? maximum : maxPoint( list, index + 1, maxVec( maximum, list[index] ));
|
||||
|
||||
//Returns the pcb position and dimensions
|
||||
function pcbPosition(boardType = UNO) = minPoint(boardShapes[boardType]);
|
||||
function pcbDimensions(boardType = UNO) = maxPoint(boardShapes[boardType]) - minPoint(boardShapes[boardType]) + [0, 0, pcbHeight];
|
||||
|
||||
//Returns the position of the box containing all components and its dimensions
|
||||
function componentsPosition(boardType = UNO) = minCompPoint(components[boardType]) + [0, 0, pcbHeight];
|
||||
function componentsDimensions(boardType = UNO) = maxCompPoint(components[boardType]) - minCompPoint(components[boardType]);
|
||||
|
||||
//Returns the position and dimensions of the box containing the pcb board
|
||||
function boardPosition(boardType = UNO) =
|
||||
minCompPoint([[pcbPosition(boardType), pcbDimensions(boardType)], [componentsPosition(boardType), componentsDimensions(boardType)]]);
|
||||
function boardDimensions(boardType = UNO) =
|
||||
maxCompPoint([[pcbPosition(boardType), pcbDimensions(boardType)], [componentsPosition(boardType), componentsDimensions(boardType)]])
|
||||
- minCompPoint([[pcbPosition(boardType), pcbDimensions(boardType)], [componentsPosition(boardType), componentsDimensions(boardType)]]);
|
||||
|
||||
/******************************* BOARD SPECIFIC DATA ******************************/
|
||||
//Board IDs
|
||||
NG = 0;
|
||||
DIECIMILA = 1;
|
||||
DUEMILANOVE = 2;
|
||||
UNO = 3;
|
||||
LEONARDO = 4;
|
||||
MEGA = 5;
|
||||
MEGA2560 = 6;
|
||||
DUE = 7;
|
||||
YUN = 8;
|
||||
INTELGALILEO = 9;
|
||||
TRE = 10;
|
||||
ETHERNET = 11;
|
||||
|
||||
/********************************** MEASUREMENTS **********************************/
|
||||
pcbHeight = 1.7;
|
||||
headerWidth = 2.54;
|
||||
headerHeight = 9;
|
||||
mountingHoleRadius = 3.2 / 2;
|
||||
|
||||
ngWidth = 53.34;
|
||||
leonardoDepth = 68.58 + 1.1; //PCB depth plus offset of USB jack (1.1)
|
||||
ngDepth = 68.58 + 6.5;
|
||||
megaDepth = 101.6 + 6.5; //Coding is my business and business is good!
|
||||
dueDepth = 101.6 + 1.1;
|
||||
|
||||
arduinoHeight = 11 + pcbHeight + 0;
|
||||
|
||||
/********************************* MOUNTING HOLES *********************************/
|
||||
|
||||
//Duemilanove, Diecimila, NG and earlier
|
||||
ngHoles = [
|
||||
[ 2.54, 15.24 ],
|
||||
[ 17.78, 66.04 ],
|
||||
[ 45.72, 66.04 ]
|
||||
];
|
||||
|
||||
//Uno, Leonardo holes
|
||||
unoHoles = [
|
||||
[ 2.54, 15.24 ],
|
||||
[ 17.78, 66.04 ],
|
||||
[ 45.72, 66.04 ],
|
||||
[ 50.8, 13.97 ]
|
||||
];
|
||||
|
||||
//Due and Mega 2560
|
||||
dueHoles = [
|
||||
[ 2.54, 15.24 ],
|
||||
[ 17.78, 66.04 ],
|
||||
[ 45.72, 66.04 ],
|
||||
[ 50.8, 13.97 ],
|
||||
[ 2.54, 90.17 ],
|
||||
[ 50.8, 96.52 ]
|
||||
];
|
||||
|
||||
// Original Mega holes
|
||||
megaHoles = [
|
||||
[ 2.54, 15.24 ],
|
||||
[ 50.8, 13.97 ],
|
||||
[ 2.54, 90.17 ],
|
||||
[ 50.8, 96.52 ]
|
||||
];
|
||||
|
||||
boardHoles = [
|
||||
ngHoles, //NG
|
||||
ngHoles, //Diecimila
|
||||
ngHoles, //Duemilanove
|
||||
unoHoles, //Uno
|
||||
unoHoles, //Leonardo
|
||||
megaHoles, //Mega
|
||||
dueHoles, //Mega 2560
|
||||
dueHoles, //Due
|
||||
0, //Yun
|
||||
0, //Intel Galileo
|
||||
0, //Tre
|
||||
unoHoles //Ethernet
|
||||
];
|
||||
|
||||
/********************************** BOARD SHAPES **********************************/
|
||||
ngBoardShape = [
|
||||
[ 0.0, 0.0 ],
|
||||
[ 53.34, 0.0 ],
|
||||
[ 53.34, 66.04 ],
|
||||
[ 50.8, 66.04 ],
|
||||
[ 48.26, 68.58 ],
|
||||
[ 15.24, 68.58 ],
|
||||
[ 12.7, 66.04 ],
|
||||
[ 1.27, 66.04 ],
|
||||
[ 0.0, 64.77 ]
|
||||
];
|
||||
|
||||
megaBoardShape = [
|
||||
[ 0.0, 0.0 ],
|
||||
[ 53.34, 0.0 ],
|
||||
[ 53.34, 99.06 ],
|
||||
[ 52.07, 99.06 ],
|
||||
[ 49.53, 101.6 ],
|
||||
[ 15.24, 101.6 ],
|
||||
[ 12.7, 99.06 ],
|
||||
[ 2.54, 99.06 ],
|
||||
[ 0.0, 96.52 ]
|
||||
];
|
||||
|
||||
boardShapes = [
|
||||
ngBoardShape, //NG
|
||||
ngBoardShape, //Diecimila
|
||||
ngBoardShape, //Duemilanove
|
||||
ngBoardShape, //Uno
|
||||
ngBoardShape, //Leonardo
|
||||
megaBoardShape, //Mega
|
||||
megaBoardShape, //Mega 2560
|
||||
megaBoardShape, //Due
|
||||
0, //Yun
|
||||
0, //Intel Galileo
|
||||
0, //Tre
|
||||
ngBoardShape //Ethernet
|
||||
];
|
||||
|
||||
/*********************************** COMPONENTS ***********************************/
|
||||
|
||||
//Component data.
|
||||
//[position, dimensions, direction(which way would a cable attach), type(header, usb, etc.), color]
|
||||
ngComponents = [
|
||||
[[1.27, 17.526, 0], [headerWidth, headerWidth * 10, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[1.27, 44.45, 0], [headerWidth, headerWidth * 8, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 26.67, 0], [headerWidth, headerWidth * 8, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 49.53, 0], [headerWidth, headerWidth * 6, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[9.34, -6.5, 0],[12, 16, 11],[0, -1, 0], USB, "LightGray" ],
|
||||
[[40.7, -1.8, 0], [9.0, 13.2, 10.9], [0, -1, 0], POWER, "Black" ]
|
||||
];
|
||||
|
||||
etherComponents = [
|
||||
[[1.27, 17.526, 0], [headerWidth, headerWidth * 10, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[1.27, 44.45, 0], [headerWidth, headerWidth * 8, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 26.67, 0], [headerWidth, headerWidth * 8, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 49.53, 0], [headerWidth, headerWidth * 6, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[7.20, -4.4, 0],[16, 22, 13],[0, -1, 0], RJ45, "Green" ],
|
||||
[[40.7, -1.8, 0], [9.0, 13.2, 10.9], [0, -1, 0], POWER, "Black" ]
|
||||
];
|
||||
|
||||
leonardoComponents = [
|
||||
[[1.27, 17.526, 0], [headerWidth, headerWidth * 10, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[1.27, 44.45, 0], [headerWidth, headerWidth * 8, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 26.67, 0], [headerWidth, headerWidth * 8, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 49.53, 0], [headerWidth, headerWidth * 6, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[11.5, -1.1, 0],[7.5, 5.9, 3],[0, -1, 0], USB, "LightGray" ],
|
||||
[[40.7, -1.8, 0], [9.0, 13.2, 10.9], [0, -1, 0], POWER, "Black" ]
|
||||
];
|
||||
|
||||
megaComponents = [
|
||||
[[1.27, 22.86, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[1.27, 44.45, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[1.27, 67.31, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[49.53, 31.75, 0], [headerWidth, headerWidth * 6, headerHeight ], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[49.53, 49.53, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[49.53, 72.39, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[1.27, 92.71, 0], [headerWidth * 18, headerWidth * 2, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[9.34, -6.5, 0],[12, 16, 11],[0, -1, 0], USB, "LightGray"],
|
||||
[[40.7, -1.8, 0], [9.0, 13.2, 10.9], [0, -1, 0], POWER, "Black" ]
|
||||
];
|
||||
|
||||
mega2560Components = [
|
||||
[[1.27, 17.526, 0], [headerWidth, headerWidth * 10, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[1.27, 44.45, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[1.27, 67.31, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 26.67, 0], [headerWidth, headerWidth * 8, headerHeight ], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 49.53, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[49.53, 72.39, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[1.27, 92.71, 0], [headerWidth * 18, headerWidth * 2, headerHeight], [0, 0, 1], HEADER_F, "Black" ],
|
||||
[[9.34, -6.5, 0],[12, 16, 11],[0, -1, 0], USB, "LightGray" ],
|
||||
[[40.7, -1.8, 0], [9.0, 13.2, 10.9], [0, -1, 0], POWER, "Black" ]
|
||||
];
|
||||
|
||||
dueComponents = [
|
||||
[[1.27, 17.526, 0], [headerWidth, headerWidth * 10, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[1.27, 44.45, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[1.27, 67.31, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[49.53, 26.67, 0], [headerWidth, headerWidth * 8, headerHeight ], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[49.53, 49.53, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[49.53, 72.39, 0], [headerWidth, headerWidth * 8, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[1.27, 92.71, 0], [headerWidth * 18, headerWidth * 2, headerHeight], [0, 0, 1], HEADER_F, "Black"],
|
||||
[[11.5, -1.1, 0], [7.5, 5.9, 3], [0, -1, 0], USB, "LightGray" ],
|
||||
[[27.365, -1.1, 0], [7.5, 5.9, 3], [0, -1, 0], USB, "LightGray" ],
|
||||
[[40.7, -1.8, 0], [9.0, 13.2, 10.9], [0, -1, 0], POWER, "Black" ]
|
||||
];
|
||||
|
||||
components = [
|
||||
ngComponents, //NG
|
||||
ngComponents, //Diecimila
|
||||
ngComponents, //Duemilanove
|
||||
ngComponents, //Uno
|
||||
leonardoComponents, //Leonardo
|
||||
megaComponents, //Mega
|
||||
mega2560Components, //Mega 2560
|
||||
dueComponents, //Due
|
||||
0, //Yun
|
||||
0, //Intel Galileo
|
||||
0, //Tre
|
||||
etherComponents //Ethernet
|
||||
];
|
||||
|
||||
/****************************** NON-BOARD PARAMETERS ******************************/
|
||||
|
||||
//Mounting holes
|
||||
woodscrewHeadRad = 4.6228; //Number 8 wood screw head radius
|
||||
woodscrewThreadRad = 2.1336; //Number 8 wood screw thread radius
|
||||
woodscrewHeadHeight = 2.8448; //Number 8 wood screw head height
|
|
@ -1 +1,5 @@
|
|||
gcc -g3 -O0 -o afterburner src_pc/afterburner.c
|
||||
|
||||
GCOM=`git rev-parse --short HEAD`
|
||||
|
||||
|
||||
gcc -g3 -O0 -DNO_CLOSE -DGCOM="\"g${GCOM}\"" -o afterburner src_pc/afterburner.c
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
# path to your Osx cross-compiler
|
||||
CC=~/opt/osxcross/bin/o64-clang
|
||||
|
||||
$CC -g3 -O0 -DNO_CLOSE -o afterburner_osx src_pc/afterburner.c
|
||||
GCOM=`git rev-parse --short HEAD`
|
||||
|
||||
|
||||
$CC -g3 -O0 -D_OSX_ -DNO_CLOSE -DGCOM="\"g${GCOM}\"" -o afterburner_osx src_pc/afterburner.c
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
# path to your win32 cross-compiler
|
||||
CC=~/opt/mingw32/bin/i686-w64-mingw32-gcc
|
||||
|
||||
$CC -g3 -O0 -o afterburner_w32.exe src_pc/afterburner.c -D_USE_WIN_API_
|
|
@ -1,4 +1,7 @@
|
|||
# path to your Win64 cross-compiler
|
||||
CC=~/opt/mingw64/bin/x86_64-w64-mingw32-gcc
|
||||
|
||||
$CC -g3 -O0 -o afterburner_w64.exe src_pc/afterburner.c -D_USE_WIN_API_
|
||||
GCOM=`git rev-parse --short HEAD`
|
||||
|
||||
$CC -g3 -O0 -o afterburner_w64.exe src_pc/afterburner.c -D_USE_WIN_API_ -DNO_CLOSE -DGCOM="\"g${GCOM}\""
|
||||
|
||||
|
|
After Width: | Height: | Size: 226 KiB |
After Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 302 KiB |
After Width: | Height: | Size: 315 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 294 KiB |
After Width: | Height: | Size: 440 KiB |
After Width: | Height: | Size: 875 KiB |
|
@ -0,0 +1,996 @@
|
|||
#ifndef _JTAG_XSVF_PLAYER_H_
|
||||
#define _JTAG_XSVF_PLAYER_H_
|
||||
|
||||
|
||||
/*
|
||||
Arduino JTAG Player for Afterburner GAL project
|
||||
---------------------------------------
|
||||
Adapted from JTAG library 1.0.15 by Marcelo Jimenez
|
||||
https://github.com/mrjimenez/JTAG
|
||||
|
||||
This port:
|
||||
* improves flash size on AVR MCU (about 6.5kb vs 11kb)
|
||||
|
||||
* allows to allocate JTAG internal buffers temporarily within a shared
|
||||
global buffer (heap). Define XSVF_HEAP to enable such feature:
|
||||
uint8_t heap[900];
|
||||
#define XSVF_HEAP heap
|
||||
#include "jtag_xsvf_player.h"
|
||||
|
||||
* reduces the code to a single .h file
|
||||
|
||||
Use the original JTAG libray python scripts to upload XSVF files
|
||||
from your PC:
|
||||
./xsvf -p /dev/ttyACM0 my_file.xsvf
|
||||
|
||||
Arduino usage:
|
||||
jtag_port_t jport;
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
//assign jtag pins (vref pin checks the cable is plugged in)
|
||||
jport.tms = 12;
|
||||
jport.tdi = 2;
|
||||
jport.tdo = 4;
|
||||
jport.tck = 3;
|
||||
jport.vref = 10;
|
||||
|
||||
//process XSVF data received from serial port
|
||||
jtag_play_xsvf(&jport);
|
||||
|
||||
*/
|
||||
|
||||
//value bigger than 63 may cause reading errors on AVR MCUs.
|
||||
#define XSVF_BUF_SIZE 62
|
||||
|
||||
#define XSVF_DEBUG 0
|
||||
#define XSVF_CALC_CSUM 1
|
||||
#define XSVF_IGNORE_NOMATCH 0
|
||||
|
||||
#define XCOMPLETE 0
|
||||
#define XTDOMASK 1
|
||||
#define XSIR 2
|
||||
#define XSDR 3
|
||||
#define XRUNTEST 4
|
||||
#define XRESERVED_5 5
|
||||
#define XRESERVED_6 6
|
||||
#define XREPEAT 7
|
||||
#define XSDRSIZE 8
|
||||
#define XSDRTDO 9
|
||||
#define XSETSDRMASKS 10
|
||||
#define XSDRINC 11
|
||||
#define XSDRB 12
|
||||
#define XSDRC 13
|
||||
#define XSDRE 14
|
||||
#define XSDRTDOB 15
|
||||
#define XSDRTDOC 16
|
||||
#define XSDRTDOE 17
|
||||
#define XSTATE 18
|
||||
#define XENDIR 19
|
||||
#define XENDDR 20
|
||||
#define XSIR2 21
|
||||
#define XCOMMENT 22
|
||||
#define XWAIT 23
|
||||
#define XWAITSTATE 24
|
||||
#define XTRST 28
|
||||
|
||||
#define S_MAX_CHAIN_SIZE_BYTES 129
|
||||
#define S_MAX_CHAIN_SIZE_BITS (S_MAX_CHAIN_SIZE_BYTES * 8)
|
||||
|
||||
#define STATE_RUN_TEST_IDLE 1
|
||||
#define STATE_PAUSE_DR 6
|
||||
#define STATE_PAUSE_IR 13
|
||||
|
||||
#define ERR_IO 1
|
||||
#define ERR_XSIR_SIZE 2
|
||||
#define ERR_XSDRSIZE 3
|
||||
#define ERR_XENDIR 4
|
||||
#define ERR_XENDDR 5
|
||||
#define ERR_XSDR 6
|
||||
#define ERR_INSTR_NOT_IMPLEMENTED 99
|
||||
#define ERR_DR_CHECK_FAILED 101
|
||||
|
||||
|
||||
/*
|
||||
* Low nibble : TMS == 0
|
||||
* High nibble: TMS == 1
|
||||
*/
|
||||
|
||||
#define TMS_T(TMS_HIGH_STATE, TMS_LOW_STATE) (((TMS_HIGH_STATE) << 4) | (TMS_LOW_STATE))
|
||||
|
||||
#define XSTATE_TEST_LOGIC_RESET 0
|
||||
#define XSTATE_RUN_TEST_IDLE 1
|
||||
#define XSTATE_SELECT_DR_SCAN 2
|
||||
#define XSTATE_CAPTURE_DR 3
|
||||
#define XSTATE_SHIFT_DR 4
|
||||
#define XSTATE_EXIT1_DR 5
|
||||
#define XSTATE_PAUSE_DR 6
|
||||
#define XSTATE_EXIT2_DR 7
|
||||
#define XSTATE_UPDATE_DR 8
|
||||
#define XSTATE_SELECT_IR_SCAN 9
|
||||
#define XSTATE_CAPTURE_IR 10
|
||||
#define XSTATE_SHIFT_IR 11
|
||||
#define XSTATE_EXIT1_IR 12
|
||||
#define XSTATE_PAUSE_IR 13
|
||||
#define XSTATE_EXIT2_IR 14
|
||||
#define XSTATE_UPDATE_IR 15
|
||||
|
||||
#define TMS_T00 /* STATE_TEST_LOGIC_RESET */ TMS_T(XSTATE_TEST_LOGIC_RESET, XSTATE_RUN_TEST_IDLE)
|
||||
#define TMS_T01 /* STATE_RUN_TEST_IDLE */ TMS_T(XSTATE_SELECT_DR_SCAN, XSTATE_RUN_TEST_IDLE)
|
||||
#define TMS_T02 /* STATE_SELECT_DR_SCAN */ TMS_T(XSTATE_SELECT_IR_SCAN, XSTATE_CAPTURE_DR)
|
||||
#define TMS_T03 /* STATE_CAPTURE_DR */ TMS_T(XSTATE_EXIT1_DR, XSTATE_SHIFT_DR)
|
||||
#define TMS_T04 /* STATE_SHIFT_DR */ TMS_T(XSTATE_EXIT1_DR, XSTATE_SHIFT_DR)
|
||||
#define TMS_T05 /* STATE_EXIT1_DR */ TMS_T(XSTATE_UPDATE_DR, XSTATE_PAUSE_DR)
|
||||
#define TMS_T06 /* STATE_PAUSE_DR */ TMS_T(XSTATE_EXIT2_DR, XSTATE_PAUSE_DR)
|
||||
#define TMS_T07 /* STATE_EXIT2_DR */ TMS_T(XSTATE_UPDATE_DR, XSTATE_SHIFT_DR)
|
||||
#define TMS_T08 /* STATE_UPDATE_DR */ TMS_T(XSTATE_SELECT_DR_SCAN, XSTATE_RUN_TEST_IDLE)
|
||||
#define TMS_T09 /* STATE_SELECT_IR_SCAN */ TMS_T(XSTATE_TEST_LOGIC_RESET, XSTATE_CAPTURE_IR)
|
||||
#define TMS_T10 /* STATE_CAPTURE_IR */ TMS_T(XSTATE_EXIT1_IR, XSTATE_SHIFT_IR)
|
||||
#define TMS_T11 /* STATE_SHIFT_IR */ TMS_T(XSTATE_EXIT1_IR, XSTATE_SHIFT_IR)
|
||||
#define TMS_T12 /* STATE_EXIT1_IR */ TMS_T(XSTATE_UPDATE_IR, XSTATE_PAUSE_IR)
|
||||
#define TMS_T13 /* STATE_PAUSE_IR */ TMS_T(XSTATE_EXIT2_IR, XSTATE_PAUSE_IR)
|
||||
#define TMS_T14 /* STATE_EXIT2_IR */ TMS_T(XSTATE_UPDATE_IR, XSTATE_SHIFT_IR)
|
||||
#define TMS_T15 /* STATE_UPDATE_IR */ TMS_T(XSTATE_SELECT_DR_SCAN, XSTATE_RUN_TEST_IDLE)
|
||||
|
||||
|
||||
#define BITSTR(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) ( \
|
||||
((uint16_t)(A) << 15) | \
|
||||
((uint16_t)(B) << 14) | \
|
||||
((uint16_t)(C) << 13) | \
|
||||
((uint16_t)(D) << 12) | \
|
||||
((uint16_t)(E) << 11) | \
|
||||
((uint16_t)(F) << 10) | \
|
||||
((uint16_t)(G) << 9) | \
|
||||
((uint16_t)(H) << 8) | \
|
||||
((uint16_t)(I) << 7) | \
|
||||
((uint16_t)(J) << 6) | \
|
||||
((uint16_t)(K) << 5) | \
|
||||
((uint16_t)(L) << 4) | \
|
||||
((uint16_t)(M) << 3) | \
|
||||
((uint16_t)(N) << 2) | \
|
||||
((uint16_t)(O) << 1) | \
|
||||
((uint16_t)(P) << 0) )
|
||||
|
||||
/*
|
||||
* The index of this vector is the current state. The i-th bit tells you the
|
||||
* value TMS must assume in order to go to state "i".
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
| | || F | E | D | C || B | A | 9 | 8 || 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 || HEX |
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
| STATE_TEST_LOGIC_RESET | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 1 || 0x0001 |
|
||||
| STATE_RUN_TEST_IDLE | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFFFD |
|
||||
| STATE_SELECT_DR_SCAN | 2 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 0 | 0 | 0 | 0 || 0 | x | 1 | 1 || 0xFE03 |
|
||||
| STATE_CAPTURE_DR | 3 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || x | 1 | 1 | 1 || 0xFFE7 |
|
||||
| STATE_SHIFT_DR | 4 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 1 | 1 | 1 | 1 || 0xFFEF |
|
||||
| STATE_EXIT1_DR | 5 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0 | 0 | x | 0 || 1 | 1 | 1 | 1 || 0xFF0F |
|
||||
| STATE_PAUSE_DR | 6 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 0 | 1 | 1 || 1 | 1 | 1 | 1 || 0xFFBF |
|
||||
| STATE_EXIT2_DR | 7 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || x | 0 | 0 | 0 || 1 | 1 | 1 | 1 || 0xFF0F |
|
||||
| STATE_UPDATE_DR | 8 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | x || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFEFD |
|
||||
| STATE_SELECT_IR_SCAN | 9 || 0 | 0 | 0 | 0 || 0 | 0 | x | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x01FF |
|
||||
| STATE_CAPTURE_IR | A || 1 | 1 | 1 | 1 || 0 | x | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF3FF |
|
||||
| STATE_SHIFT_IR | B || 1 | 1 | 1 | 1 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF7FF |
|
||||
| STATE_EXIT1_IR | C || 1 | 0 | 0 | x || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF |
|
||||
| STATE_PAUSE_IR | D || 1 | 1 | 0 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xDFFF |
|
||||
| STATE_EXIT2_IR | E || 1 | x | 0 | 0 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF |
|
||||
| STATE_UPDATE_IR | F || x | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0x7FFD |
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*/
|
||||
|
||||
#define BS00 /* STATE_TEST_LOGIC_RESET */ BITSTR( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 )
|
||||
#define BS01 /* STATE_RUN_TEST_IDLE */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 )
|
||||
#define BS02 /* STATE_SELECT_DR_SCAN */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 )
|
||||
#define BS03 /* STATE_CAPTURE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1 )
|
||||
#define BS04 /* STATE_SHIFT_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 )
|
||||
#define BS05 /* STATE_EXIT1_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
#define BS06 /* STATE_PAUSE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 )
|
||||
#define BS07 /* STATE_EXIT2_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 )
|
||||
#define BS08 /* STATE_UPDATE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 )
|
||||
#define BS09 /* STATE_SELECT_IR_SCAN */ BITSTR( 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
|
||||
#define BS10 /* STATE_CAPTURE_IR */ BITSTR( 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
|
||||
#define BS11 /* STATE_SHIFT_IR */ BITSTR( 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
|
||||
#define BS12 /* STATE_EXIT1_IR */ BITSTR( 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
|
||||
#define BS13 /* STATE_PAUSE_IR */ BITSTR( 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
|
||||
#define BS14 /* STATE_EXIT2_IR */ BITSTR( 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
|
||||
#define BS15 /* STATE_UPDATE_IR */ BITSTR( 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 )
|
||||
|
||||
|
||||
typedef struct xsvf_t {
|
||||
uint8_t* xsvf_tdo_mask;
|
||||
uint8_t* xsvf_tdi;
|
||||
uint8_t* xsvf_tdo;
|
||||
uint8_t* xsvf_tdo_expected;
|
||||
uint8_t* xsvf_address_mask;
|
||||
uint8_t* xsvf_data_mask;
|
||||
|
||||
uint32_t rdpos;
|
||||
uint32_t wrpos;
|
||||
|
||||
#if XSVF_CALC_CSUM
|
||||
uint32_t csum;
|
||||
#endif
|
||||
|
||||
uint16_t instruction_counter;
|
||||
uint8_t error;
|
||||
uint8_t xcomplete;
|
||||
|
||||
uint16_t sirsize_bits;
|
||||
uint16_t sirsize_bytes;
|
||||
|
||||
uint32_t sdrsize_bits;
|
||||
uint32_t sdrsize_bytes;
|
||||
uint32_t runtest;
|
||||
|
||||
uint8_t repeat;
|
||||
uint8_t next_state;
|
||||
uint8_t endir_state;
|
||||
uint8_t enddr_state;
|
||||
|
||||
uint32_t wait_time_usecs;
|
||||
uint8_t wait_start_state;
|
||||
uint8_t wait_end_state;
|
||||
uint8_t jtag_current_state;
|
||||
|
||||
} xsvf_t;
|
||||
|
||||
#ifdef XSVF_HEAP
|
||||
// variables will be allocated on heap
|
||||
uint8_t* xsvf_buf;
|
||||
xsvf_t* xsvf;
|
||||
uint8_t* xsvf_tms_transitions;
|
||||
uint16_t* xsvf_tms_map;
|
||||
#else /* XSVF_HEAP */
|
||||
// variables allocated globally
|
||||
uint8_t xsvf_buf[XSVF_BUF_SIZE];
|
||||
uint8_t xsvf_tdo_mask[S_MAX_CHAIN_SIZE_BYTES];
|
||||
uint8_t xsvf_tdi[S_MAX_CHAIN_SIZE_BYTES];
|
||||
uint8_t xsvf_tdo[S_MAX_CHAIN_SIZE_BYTES];
|
||||
uint8_t xsvf_tdo_expected[S_MAX_CHAIN_SIZE_BYTES];
|
||||
uint8_t xsvf_address_mask[S_MAX_CHAIN_SIZE_BYTES];
|
||||
uint8_t xsvf_data_mask[S_MAX_CHAIN_SIZE_BYTES];
|
||||
xsvf_t xsvf_context;
|
||||
xsvf_t* xsvf = &xsvf_context;
|
||||
|
||||
static const uint8_t xsvf_tms_transitions[] = {
|
||||
TMS_T00, TMS_T01, TMS_T02, TMS_T03, TMS_T04, TMS_T05, TMS_T06, TMS_T07,
|
||||
TMS_T08, TMS_T09, TMS_T10, TMS_T11, TMS_T12, TMS_T13, TMS_T14, TMS_T15,
|
||||
};
|
||||
static const uint16_t xsvf_tms_map[] = {
|
||||
BS00, BS01, BS02, BS03, BS04, BS05, BS06, BS07,
|
||||
BS08, BS09, BS10, BS11, BS12, BS13, BS14, BS15
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct jtag_port_t {
|
||||
uint8_t tms;
|
||||
uint8_t tdi;
|
||||
uint8_t tdo;
|
||||
uint8_t tck;
|
||||
uint8_t vref;
|
||||
} jtag_port_t;
|
||||
|
||||
static void jtag_port_init(jtag_port_t* port) {
|
||||
pinMode(port->tms, OUTPUT);
|
||||
pinMode(port->tdi, OUTPUT);
|
||||
pinMode(port->tck, OUTPUT);
|
||||
pinMode(port->tdo, INPUT);
|
||||
pinMode(port->vref, INPUT);
|
||||
}
|
||||
|
||||
static void jtag_port_pulse_clock(jtag_port_t* port) {
|
||||
digitalWrite(port->tck, 0);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(port->tck, 1);
|
||||
}
|
||||
|
||||
static uint8_t jtag_port_pulse_clock_read_tdo(jtag_port_t* port) {
|
||||
uint8_t val;
|
||||
digitalWrite(port->tck, 0);
|
||||
delayMicroseconds(1);
|
||||
val = digitalRead(port->tdo);
|
||||
digitalWrite(port->tck, 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void jtag_port_set_tms(jtag_port_t* port, uint8_t val) {
|
||||
digitalWrite(port->tms, val);
|
||||
}
|
||||
static inline void jtag_port_set_tdi(jtag_port_t* port, uint8_t val) {
|
||||
digitalWrite(port->tdi, val);
|
||||
}
|
||||
|
||||
static inline uint8_t jtag_port_get_veref(jtag_port_t* port) {
|
||||
return digitalRead(port->vref);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t xsvf_player_next_byte(void) {
|
||||
uint8_t retry = 16;
|
||||
uint8_t pos = xsvf->rdpos % XSVF_BUF_SIZE;
|
||||
|
||||
if (xsvf->wrpos == xsvf->rdpos) {
|
||||
size_t r = 0;
|
||||
while (r == 0) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println("D<<< req read"); // request to receive BUF size bytes
|
||||
#endif
|
||||
Serial.println(F("$062")); // request to receive BUF size bytes
|
||||
r = Serial.readBytes(xsvf_buf + pos, XSVF_BUF_SIZE - pos);
|
||||
#if XSVF_DEBUG
|
||||
Serial.print("D<<< read "); // request to receive BUF size bytes
|
||||
Serial.println(r, DEC); // request to receive BUF size bytes
|
||||
#endif
|
||||
if (r == 0) {
|
||||
retry --;
|
||||
if (retry == 0) {
|
||||
xsvf->error = 1;
|
||||
return 0;
|
||||
}
|
||||
delay(1);
|
||||
} else {
|
||||
xsvf->wrpos += r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xsvf->rdpos++;
|
||||
#if XSVF_DEBUG
|
||||
Serial.print(F("D BYTE "));
|
||||
Serial.print(xsvf_buf[pos], DEC);
|
||||
Serial.print(F(" 0x"));
|
||||
Serial.println(xsvf_buf[pos], HEX);
|
||||
#endif
|
||||
#if XSVF_CALC_CSUM
|
||||
xsvf->csum += xsvf_buf[pos];
|
||||
#endif
|
||||
|
||||
return xsvf_buf[pos];
|
||||
}
|
||||
|
||||
static uint8_t xsvf_player_get_next_byte(void) {
|
||||
return xsvf_player_next_byte();
|
||||
}
|
||||
/*
|
||||
static uint16_t xsvf_player_get_next_word(void) {
|
||||
uint16_t i = xsvf_player_next_byte();
|
||||
i <<= 8;
|
||||
i |= xsvf_player_next_byte();
|
||||
return i;
|
||||
}
|
||||
*/
|
||||
|
||||
static uint32_t xsvf_player_get_next_long(void) {
|
||||
uint32_t i = xsvf_player_next_byte();
|
||||
i <<= 8;
|
||||
i |= xsvf_player_next_byte();
|
||||
i <<= 8;
|
||||
i |= xsvf_player_next_byte();
|
||||
i <<= 8;
|
||||
i |= xsvf_player_next_byte();
|
||||
return i;
|
||||
}
|
||||
|
||||
static void xsvf_player_get_next_bytes(uint8_t* data, uint32_t count) {
|
||||
while(count--) {
|
||||
*data++ = xsvf_player_next_byte();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XSVF_HEAP
|
||||
static uint32_t xsvf_heap_pos(uint32_t* pos, uint16_t size) {
|
||||
uint32_t heap_pos = *pos;
|
||||
//allocate on 4 byte boundaries
|
||||
heap_pos = (heap_pos + 3) & 0xFFFFFFFC;
|
||||
*pos = heap_pos + size;
|
||||
return heap_pos;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void xsvf_clear() {
|
||||
uint16_t i;
|
||||
uint8_t* d = (uint8_t*) xsvf;
|
||||
//clear the xsvf data in RAM
|
||||
i = sizeof(xsvf_t);
|
||||
while(i) {
|
||||
i--;
|
||||
d[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void xsvf_player_init(jtag_port_t* port) {
|
||||
jtag_port_init(port);
|
||||
|
||||
#ifdef XSVF_HEAP
|
||||
{
|
||||
// variables allocated on the heap
|
||||
uint32_t heap_pos = (uint32_t) XSVF_HEAP;
|
||||
|
||||
xsvf = (xsvf_t*) xsvf_heap_pos(&heap_pos, sizeof(xsvf_t));
|
||||
xsvf_buf = (uint8_t*) xsvf_heap_pos(&heap_pos, XSVF_BUF_SIZE);
|
||||
|
||||
xsvf_clear();
|
||||
|
||||
xsvf->xsvf_tdo_mask = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES);
|
||||
xsvf->xsvf_tdi = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES);
|
||||
xsvf->xsvf_tdo = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES);
|
||||
xsvf->xsvf_tdo_expected = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES);
|
||||
xsvf->xsvf_address_mask = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES);
|
||||
xsvf->xsvf_data_mask = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES);
|
||||
xsvf_tms_transitions = (uint8_t*) xsvf_heap_pos(&heap_pos, 16);
|
||||
xsvf_tms_map = (uint16_t*) xsvf_heap_pos(&heap_pos, 32);
|
||||
|
||||
if (heap_pos - ((uint32_t)XSVF_HEAP) > sizeof(XSVF_HEAP)) {
|
||||
Serial.print(F("Q-1,ERROR: Heap is small:"));
|
||||
Serial.println(heap_pos - ((uint32_t)XSVF_HEAP), DEC);
|
||||
return;
|
||||
}
|
||||
|
||||
//set up TM transitions
|
||||
xsvf_tms_transitions[0] = TMS_T00;
|
||||
xsvf_tms_transitions[1] = TMS_T01;
|
||||
xsvf_tms_transitions[2] = TMS_T02;
|
||||
xsvf_tms_transitions[3] = TMS_T03;
|
||||
xsvf_tms_transitions[4] = TMS_T04;
|
||||
xsvf_tms_transitions[5] = TMS_T05;
|
||||
xsvf_tms_transitions[6] = TMS_T06;
|
||||
xsvf_tms_transitions[7] = TMS_T07;
|
||||
xsvf_tms_transitions[8] = TMS_T08;
|
||||
xsvf_tms_transitions[9] = TMS_T09;
|
||||
xsvf_tms_transitions[10] = TMS_T10;
|
||||
xsvf_tms_transitions[11] = TMS_T11;
|
||||
xsvf_tms_transitions[12] = TMS_T12;
|
||||
xsvf_tms_transitions[13] = TMS_T13;
|
||||
xsvf_tms_transitions[14] = TMS_T14;
|
||||
xsvf_tms_transitions[15] = TMS_T15;
|
||||
|
||||
//set up bitstream map
|
||||
xsvf_tms_map[0] = BS00;
|
||||
xsvf_tms_map[1] = BS01;
|
||||
xsvf_tms_map[2] = BS02;
|
||||
xsvf_tms_map[3] = BS03;
|
||||
xsvf_tms_map[4] = BS04;
|
||||
xsvf_tms_map[5] = BS05;
|
||||
xsvf_tms_map[6] = BS06;
|
||||
xsvf_tms_map[7] = BS07;
|
||||
xsvf_tms_map[8] = BS08;
|
||||
xsvf_tms_map[9] = BS09;
|
||||
xsvf_tms_map[10] = BS10;
|
||||
xsvf_tms_map[11] = BS11;
|
||||
xsvf_tms_map[12] = BS12;
|
||||
xsvf_tms_map[13] = BS13;
|
||||
xsvf_tms_map[14] = BS14;
|
||||
xsvf_tms_map[15] = BS15;
|
||||
|
||||
}
|
||||
#else
|
||||
{
|
||||
xsvf_clear();
|
||||
|
||||
xsvf->xsvf_tdo_mask = xsvf_tdo_mask;
|
||||
xsvf->xsvf_tdi = xsvf_tdi;
|
||||
xsvf->xsvf_tdo = xsvf_tdo;
|
||||
xsvf->xsvf_tdo_expected = xsvf_tdo_expected;
|
||||
xsvf->xsvf_address_mask = xsvf_address_mask;
|
||||
xsvf->xsvf_data_mask = xsvf_data_mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
xsvf->repeat = 32;
|
||||
xsvf->endir_state = XSTATE_RUN_TEST_IDLE;
|
||||
xsvf->enddr_state = STATE_RUN_TEST_IDLE;
|
||||
}
|
||||
|
||||
|
||||
static void xsvf_jtagtap_state_ack(uint8_t tms) {
|
||||
tms <<= 2; // either 0 or 4
|
||||
xsvf->jtag_current_state = (xsvf_tms_transitions[xsvf->jtag_current_state] >> tms) & 0xf;
|
||||
}
|
||||
|
||||
static void xsvf_jtagtap_shift_td(
|
||||
jtag_port_t* port,
|
||||
uint8_t *input_data,
|
||||
uint8_t *output_data,
|
||||
uint32_t data_bits,
|
||||
uint8_t must_end)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint32_t bit_count = data_bits;
|
||||
uint32_t byte_count = (data_bits+ 7) >> 3;
|
||||
|
||||
for (i = 0; i < byte_count; ++i) {
|
||||
uint8_t byte_out = input_data[byte_count - 1 - i];
|
||||
uint8_t tdo_byte = 0;
|
||||
for (j = 0; j < 8 && bit_count-- > 0; ++j) {
|
||||
uint8_t tdo;
|
||||
if (bit_count == 0 && must_end) {
|
||||
jtag_port_set_tms(port, 1);
|
||||
xsvf_jtagtap_state_ack(1);
|
||||
}
|
||||
jtag_port_set_tdi(port, byte_out & 1);
|
||||
byte_out >>= 1;
|
||||
tdo = jtag_port_pulse_clock_read_tdo(port);
|
||||
tdo_byte |= tdo << j;
|
||||
}
|
||||
output_data[byte_count - 1 - i] = tdo_byte;
|
||||
}
|
||||
}
|
||||
|
||||
static void xsvf_jtagtap_state_step(jtag_port_t* port, uint8_t tms) {
|
||||
jtag_port_set_tms(port, tms);
|
||||
jtag_port_pulse_clock(port);
|
||||
xsvf_jtagtap_state_ack(tms);
|
||||
}
|
||||
|
||||
static void xsvf_jtagtap_state_goto(jtag_port_t* port, uint8_t state) {
|
||||
if (xsvf->error) {
|
||||
return;
|
||||
}
|
||||
if (state == XSTATE_TEST_LOGIC_RESET) {
|
||||
uint8_t i;
|
||||
for (i = 0; i < 5; ++i) {
|
||||
xsvf_jtagtap_state_step(port, 1);
|
||||
}
|
||||
} else {
|
||||
while (xsvf->jtag_current_state != state) {
|
||||
xsvf_jtagtap_state_step(port, (xsvf_tms_map[xsvf->jtag_current_state] >> state) & 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xsvf_jtagtap_wait_time(jtag_port_t* port, uint32_t microseconds, uint8_t wait_clock) {
|
||||
uint32_t until;
|
||||
|
||||
if (xsvf->error) {
|
||||
return;
|
||||
}
|
||||
|
||||
until = micros() + microseconds;
|
||||
if (wait_clock) {
|
||||
while (microseconds--) {
|
||||
jtag_port_pulse_clock(port);
|
||||
}
|
||||
}
|
||||
while (micros() < until) {
|
||||
jtag_port_pulse_clock(port);
|
||||
}
|
||||
}
|
||||
|
||||
static void xsvf_jtag_sir(jtag_port_t* port) {
|
||||
if (xsvf->error) {
|
||||
return;
|
||||
}
|
||||
xsvf_jtagtap_state_goto(port, XSTATE_SHIFT_IR);
|
||||
xsvf_jtagtap_shift_td(port, xsvf->xsvf_tdi, xsvf->xsvf_tdo, xsvf->sirsize_bits, 1);
|
||||
if (xsvf->runtest) {
|
||||
xsvf_jtagtap_state_goto(port, xsvf->endir_state);
|
||||
} else {
|
||||
xsvf_jtagtap_state_goto(port, XSTATE_RUN_TEST_IDLE);
|
||||
xsvf_jtagtap_wait_time(port, xsvf->runtest, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t xsvf_jtag_is_tdo_as_expected(uint8_t use_mask)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < xsvf->sdrsize_bytes; ++i) {
|
||||
uint8_t expected = xsvf->xsvf_tdo_expected[i];
|
||||
uint8_t actual = xsvf->xsvf_tdo[i];
|
||||
if (use_mask) {
|
||||
uint8_t mask = xsvf->xsvf_tdo_mask[i];
|
||||
expected &= mask;
|
||||
actual &= mask;
|
||||
}
|
||||
#if XSVF_IGNORE_NOMATCH != 1
|
||||
if (expected != actual) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("D...NO MATCH!"));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("D...match!"));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define SDR_MUST_BEGIN (flags & 0b1000)
|
||||
#define SDR_MUST_CHECK (flags & 0b0100)
|
||||
#define SDR_USE_MASK (flags & 0b0010)
|
||||
#define SDR_MUST_END (flags & 0b0001)
|
||||
|
||||
static uint8_t xsvf_jtag_sdr(jtag_port_t* port, uint8_t flags)
|
||||
{
|
||||
int16_t attempts_left = xsvf->repeat;
|
||||
uint8_t matched = 0;
|
||||
uint8_t must_end = SDR_MUST_END;
|
||||
uint8_t must_check = SDR_MUST_CHECK;
|
||||
uint8_t use_mask = SDR_USE_MASK;
|
||||
|
||||
if (xsvf->error) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SDR_MUST_BEGIN) {
|
||||
xsvf_jtagtap_state_goto(port, XSTATE_SHIFT_DR);
|
||||
}
|
||||
while (!matched && attempts_left-- >= 0) {
|
||||
xsvf_jtagtap_shift_td(port, xsvf->xsvf_tdi, xsvf->xsvf_tdo, xsvf->sdrsize_bits, must_end);
|
||||
if (!must_check) {
|
||||
break;
|
||||
}
|
||||
matched = xsvf_jtag_is_tdo_as_expected(use_mask);
|
||||
if (!matched) {
|
||||
// XAP058, page 14
|
||||
xsvf_jtagtap_state_goto(port, XSTATE_PAUSE_DR);
|
||||
xsvf_jtagtap_state_goto(port, XSTATE_SHIFT_DR);
|
||||
xsvf_jtagtap_state_goto(port, XSTATE_RUN_TEST_IDLE);
|
||||
xsvf_jtagtap_wait_time(port, xsvf->runtest, 1);
|
||||
//
|
||||
xsvf_jtagtap_state_goto(port, XSTATE_SHIFT_DR);
|
||||
#if XSVF_DEBUG
|
||||
if (attempts_left >= 0) {
|
||||
Serial.print(F("D...repeating: "));
|
||||
Serial.println(xsvf->repeat - attempts_left, DEC);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (must_check && !matched) {
|
||||
xsvf->error = ERR_DR_CHECK_FAILED;
|
||||
Serial.println(F("D!DR check failed!"));
|
||||
}
|
||||
if (must_end && matched) {
|
||||
if (!xsvf->runtest) {
|
||||
xsvf_jtagtap_state_goto(port, xsvf->enddr_state);
|
||||
} else {
|
||||
xsvf_jtagtap_state_goto(port, XSTATE_RUN_TEST_IDLE);
|
||||
xsvf_jtagtap_wait_time(port, xsvf->runtest, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return !must_check || (must_check && matched);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Reads the next instruction from the serial port. Also reads any
|
||||
* remaining instruction parameters into the instruction buffer.
|
||||
*/
|
||||
static uint8_t xsvf_player_handle_next_instruction(jtag_port_t* port) {
|
||||
uint8_t instruction = xsvf_player_next_byte();
|
||||
if (xsvf->error) {
|
||||
return ERR_IO; // failure
|
||||
}
|
||||
xsvf->instruction_counter++;
|
||||
|
||||
#if XSVF_DEBUG
|
||||
Serial.print(F("D INSTR "));
|
||||
Serial.print(xsvf->instruction_counter, DEC);
|
||||
Serial.print(F(" (0x"));
|
||||
Serial.print(instruction, HEX);
|
||||
Serial.print(F("): "));
|
||||
#endif
|
||||
|
||||
//do not use switch as it uses RAM
|
||||
// ---[COMPLETE ] --------------------------------------------
|
||||
if (instruction == XCOMPLETE) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XCOMPLETE"));
|
||||
#endif
|
||||
xsvf->xcomplete = 1;
|
||||
} else
|
||||
|
||||
// ---[TDO MASK] --------------------------------------------
|
||||
if (instruction == XTDOMASK) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XTDOMASK"));
|
||||
#endif
|
||||
xsvf_player_get_next_bytes(xsvf->xsvf_tdo_mask, xsvf->sdrsize_bytes);
|
||||
} else
|
||||
|
||||
// ---[SIR SIR2] --------------------------------------------
|
||||
if (instruction == XSIR || instruction == XSIR2) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(instruction == XSIR ? F("XSIR") : F("XSIR2"));
|
||||
#endif
|
||||
xsvf->sirsize_bits = xsvf_player_get_next_byte();
|
||||
if (instruction == XSIR2) {
|
||||
xsvf->sirsize_bits <= 8;
|
||||
xsvf->sirsize_bits |= xsvf_player_get_next_byte();
|
||||
}
|
||||
xsvf->sirsize_bytes = (xsvf->sirsize_bits + 7) >> 3;
|
||||
if (xsvf->sirsize_bytes > S_MAX_CHAIN_SIZE_BYTES) {
|
||||
return ERR_XSIR_SIZE;
|
||||
}
|
||||
xsvf_player_get_next_bytes(xsvf->xsvf_tdi, xsvf->sirsize_bytes);
|
||||
xsvf_jtag_sir(port);
|
||||
} else
|
||||
|
||||
// ---[SDR ] --------------------------------------------
|
||||
if (instruction == XSDR || (instruction >= XSDRB && instruction <= XSDRE)) {
|
||||
uint8_t flags = 0b1111;
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XSDRx"));
|
||||
#endif
|
||||
xsvf_player_get_next_bytes(xsvf->xsvf_tdi, xsvf->sdrsize_bytes);
|
||||
if (instruction != XSDR) {
|
||||
flags = (instruction == XSDRB) ? 0b1000 : (instruction == XSDRC) ? 0b0000 : 0b0001;
|
||||
}
|
||||
if (!xsvf_jtag_sdr(port, flags)) {
|
||||
xsvf->error = ERR_XSDR;
|
||||
}
|
||||
} else
|
||||
|
||||
// ---[RUN TEST ] --------------------------------------------
|
||||
if (instruction == XRUNTEST) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XRUNTEST"));
|
||||
#endif
|
||||
xsvf->runtest = xsvf_player_get_next_long();
|
||||
} else
|
||||
// ---[REPEAT ] --------------------------------------------
|
||||
if (instruction == XREPEAT) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XREPEAT"));
|
||||
#endif
|
||||
xsvf->repeat = xsvf_player_get_next_byte();
|
||||
} else
|
||||
|
||||
// ---[SDRSIZE ] --------------------------------------------
|
||||
if (instruction == XSDRSIZE) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XSDRSIZE"));
|
||||
#endif
|
||||
xsvf->sdrsize_bits = xsvf_player_get_next_long();
|
||||
xsvf->sdrsize_bytes = (xsvf->sdrsize_bits + 7) >> 3;
|
||||
if (xsvf->sdrsize_bytes > S_MAX_CHAIN_SIZE_BYTES) {
|
||||
return ERR_XSDRSIZE;
|
||||
}
|
||||
} else
|
||||
|
||||
// ---[SDRTDO ] --------------------------------------------
|
||||
if (instruction == XSDRTDO || (instruction >= XSDRTDOB && instruction <= XSDRTDOE)) {
|
||||
uint8_t flags = 0b1111;
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XSDRTDOx"));
|
||||
#endif
|
||||
xsvf_player_get_next_bytes(xsvf->xsvf_tdi, xsvf->sdrsize_bytes);
|
||||
xsvf_player_get_next_bytes(xsvf->xsvf_tdo_expected, xsvf->sdrsize_bytes);
|
||||
if (instruction != XSDRTDO) {
|
||||
flags = (instruction == XSDRTDOB) ? 0b1100 : (instruction == XSDRTDOC) ? 0b0100 : 0b0101;
|
||||
}
|
||||
if (!xsvf_jtag_sdr(port, flags)) {
|
||||
xsvf->error = ERR_XSDR;
|
||||
}
|
||||
} else
|
||||
|
||||
// ---[SET SDR MASKS ] --------------------------------------------
|
||||
if (instruction == XSETSDRMASKS) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XSETSDRMASKS"));
|
||||
#endif
|
||||
xsvf_player_get_next_bytes(xsvf->xsvf_address_mask, xsvf->sdrsize_bytes);
|
||||
xsvf_player_get_next_bytes(xsvf->xsvf_data_mask, xsvf->sdrsize_bytes);
|
||||
} else
|
||||
|
||||
// ---[SDR INC ] --------------------------------------------
|
||||
if (instruction == XSDRINC) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XSDRINC"));
|
||||
#endif
|
||||
xsvf_player_get_next_bytes(xsvf->xsvf_tdi, xsvf->sdrsize_bytes);
|
||||
// TODO - check: return false?
|
||||
} else
|
||||
|
||||
// ---[STATE ] --------------------------------------------
|
||||
if (instruction == XSTATE) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XSTATE"));
|
||||
#endif
|
||||
xsvf->next_state = xsvf_player_get_next_byte();
|
||||
xsvf_jtagtap_state_goto(port, xsvf->next_state);
|
||||
} else
|
||||
|
||||
// ---[END IR ] --------------------------------------------
|
||||
if (instruction == XENDIR) {
|
||||
uint8_t s;
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XENDIR"));
|
||||
#endif
|
||||
s = xsvf_player_get_next_byte();
|
||||
if (s == 0) {
|
||||
xsvf->endir_state = STATE_RUN_TEST_IDLE;
|
||||
} else
|
||||
if (s == 1) {
|
||||
xsvf->endir_state = STATE_PAUSE_IR;
|
||||
} else {
|
||||
return ERR_XENDIR;
|
||||
}
|
||||
} else
|
||||
|
||||
// ---[END DR ] --------------------------------------------
|
||||
if (instruction == XENDDR) {
|
||||
uint8_t s;
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XENDDR"));
|
||||
#endif
|
||||
|
||||
s = xsvf_player_get_next_byte();
|
||||
if (s == 0) {
|
||||
xsvf->enddr_state = STATE_RUN_TEST_IDLE;
|
||||
} else
|
||||
if (s == 1) {
|
||||
xsvf->enddr_state = STATE_PAUSE_DR;
|
||||
} else {
|
||||
return ERR_XENDDR;
|
||||
}
|
||||
} else
|
||||
|
||||
// ---[COMMENT ] --------------------------------------------
|
||||
if (instruction == XCOMMENT) {
|
||||
uint8_t c;
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XCOMMENT"));
|
||||
#endif
|
||||
Serial.print(F("D"));//debug message preamble
|
||||
//read the comment bytes
|
||||
do {
|
||||
c = xsvf_player_get_next_byte();
|
||||
// special feature: dump the TDO data
|
||||
if (c == '#') {
|
||||
uint8_t cnt = 0;
|
||||
uint8_t size = xsvf_player_get_next_byte() - '0';
|
||||
//dump the tdo buffer bytes
|
||||
while(cnt < size) {
|
||||
char t[4];
|
||||
uint8_t v = xsvf->xsvf_tdo[cnt];
|
||||
uint8_t x1 = v >> 4;
|
||||
v &= 0xF;
|
||||
// DEC to HEX conversion with leading zero
|
||||
t[0] = (char) (x1 < 10 ? '0' + x1 : 55 + x1 );
|
||||
t[1] = (char) (v < 10 ? '0' + v : 55 + v );
|
||||
t[2] = 0;
|
||||
Serial.print(t);
|
||||
cnt++;
|
||||
}
|
||||
} else if (c) {
|
||||
Serial.print((char)c);
|
||||
}
|
||||
} while(c);
|
||||
Serial.println();
|
||||
} else
|
||||
|
||||
// ---[WAIT ] --------------------------------------------
|
||||
if (instruction == XWAIT || instruction == XWAITSTATE) {
|
||||
uint32_t clock_cnt = 0;
|
||||
uint8_t wait_clock = 1;
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(instruction == XWAIT ? F("XWAIT") : F("XWAITSTATE"));
|
||||
#endif
|
||||
//TOOD - do we need these states to be global?
|
||||
xsvf->wait_start_state = xsvf_player_get_next_byte();
|
||||
xsvf->wait_end_state = xsvf_player_get_next_byte();
|
||||
if (instruction == XWAITSTATE) {
|
||||
clock_cnt = xsvf_player_get_next_long();
|
||||
wait_clock = clock_cnt > 0 ? 1 : 0;
|
||||
}
|
||||
#if XSVF_DEBUG
|
||||
Serial.print(F("Dclock:"));
|
||||
Serial.println(clock_cnt, DEC);
|
||||
#endif
|
||||
xsvf->wait_time_usecs = xsvf_player_get_next_long();
|
||||
#if XSVF_DEBUG
|
||||
Serial.print(F("Dmicros:"));
|
||||
Serial.println( xsvf->wait_time_usecs, DEC);
|
||||
#endif
|
||||
|
||||
xsvf_jtagtap_state_goto(port, xsvf->wait_start_state);
|
||||
// happens only during XWAITSTATE
|
||||
while (clock_cnt) {
|
||||
jtag_port_pulse_clock(port);
|
||||
clock_cnt--;
|
||||
}
|
||||
xsvf_jtagtap_wait_time(port, xsvf->wait_time_usecs, wait_clock);
|
||||
xsvf_jtagtap_state_goto(port, xsvf->wait_end_state);
|
||||
|
||||
} else
|
||||
// ---[TRST - test line reset] --------------------------------------------
|
||||
if (instruction == XTRST) {
|
||||
#if XSVF_DEBUG
|
||||
Serial.println(F("XTRST"));
|
||||
#endif
|
||||
//read test reset mode (0-on, 1-off, 2-Z, 3-Absent)
|
||||
xsvf_player_get_next_byte();
|
||||
} else
|
||||
// ---[UNKNOWN ] --------------------------------------------
|
||||
{
|
||||
#if XSVF_DEBUG
|
||||
Serial.print(F("XUNKNOWN:"));
|
||||
Serial.println(instruction, DEC);
|
||||
#endif
|
||||
//unimplemented instruction
|
||||
return ERR_INSTR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if (xsvf->error) {
|
||||
return xsvf->error; // failure
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void jtag_play_xsvf(jtag_port_t* port)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
uint8_t ret;
|
||||
|
||||
xsvf_player_init(port);
|
||||
|
||||
//check xref is high
|
||||
if (!jtag_port_get_veref(port)) {
|
||||
Serial.println(F("Q-255,JTAG not connected"));
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println(F("RXSVF")); //announce ready to receive XSVF stream
|
||||
|
||||
while(1) {
|
||||
n++;
|
||||
ret = xsvf_player_handle_next_instruction(port);
|
||||
if (ret) {
|
||||
Serial.print(F("Q-"));
|
||||
Serial.print(ret, DEC );
|
||||
Serial.println(F(",Fail"));
|
||||
break;
|
||||
} else {
|
||||
if (xsvf->xcomplete) {
|
||||
Serial.println(F("!Success"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Serial.print(F("!Processed instr:"));
|
||||
Serial.println(xsvf->instruction_counter, DEC);
|
||||
|
||||
#if XSVF_CALC_CSUM
|
||||
Serial.print(F("!sum: 0x"));
|
||||
// print leading zeros in the check sum hex value
|
||||
{
|
||||
uint32_t i = 0xF0000000;
|
||||
while((!(xsvf->csum & i)) && i) {
|
||||
Serial.print(F("0"));
|
||||
i >>= 4;
|
||||
}
|
||||
}
|
||||
Serial.print(xsvf->csum, HEX);
|
||||
Serial.print(F("/"));
|
||||
Serial.println(xsvf->rdpos, DEC);
|
||||
#endif /* XSVF_CALC_CSUM */
|
||||
|
||||
if (xsvf->xcomplete) {
|
||||
Serial.println(F("Q-0,OK"));
|
||||
}
|
||||
//the 3 pins must be low or else the vref might be triggered next time
|
||||
digitalWrite(port->tms, 0);
|
||||
digitalWrite(port->tdi, 0);
|
||||
digitalWrite(port->tck, 0);
|
||||
delay(100);
|
||||
|
||||
// put the jtag port pins into High-Z (vref already is input)
|
||||
pinMode(port->tms, INPUT);
|
||||
pinMode(port->tdi, INPUT);
|
||||
pinMode(port->tck, INPUT);
|
||||
pinMode(port->tdo, INPUT);
|
||||
}
|
||||
|
||||
|
||||
#endif /*_JTAG_XSVF_PLAYER_H_*/
|
|
@ -9,9 +9,9 @@ Grid[25.00mil 0.0000 0.0000 1]
|
|||
PolyArea[3100.006200]
|
||||
Thermal[0.500000]
|
||||
DRC[7.00mil 7.00mil 7.00mil 7.00mil 15.00mil 10.00mil]
|
||||
Flags("nameonpcb,uniquename,clearnew,snappin")
|
||||
Flags("nameonpcb,uniquename,clearnew,newfullpoly,snappin,thindrawpoly")
|
||||
Groups("1,c:2,s:3:4:5:6:7:8")
|
||||
Styles["Signal,10.00mil,24.00mil,12.00mil,7.00mil:Power,20.00mil,50.00mil,28.00mil,7.00mil:Fat,25.00mil,60.00mil,35.00mil,10.00mil:Skinny,7.00mil,24.00mil,12.00mil,7.00mil"]
|
||||
Styles["Signal,10.00mil,24.00mil,12.00mil,7.00mil:Power,20.00mil,50.00mil,28.00mil,7.00mil:Fat,25.00mil,60.00mil,35.00mil,10.00mil:Skinny,12.00mil,24.00mil,12.00mil,7.00mil"]
|
||||
Symbol[' ' 18.00mil]
|
||||
(
|
||||
)
|
||||
|
@ -786,429 +786,531 @@ Symbol['~' 12.00mil]
|
|||
)
|
||||
Attribute("PCB::grid::unit" "mil")
|
||||
Attribute("PCB::grid::size" "25.00mil")
|
||||
Via[1300.00mil 2600.00mil 24.00mil 14.00mil 0.0000 12.00mil "" "thermal(0X,1X)"]
|
||||
Via[1300.00mil 3100.00mil 24.00mil 14.00mil 0.0000 12.00mil "" "thermal(0X,1X)"]
|
||||
Via[1350.00mil 1750.00mil 24.00mil 14.00mil 0.0000 12.00mil "" "thermal(0X,1X)"]
|
||||
Via[1050.00mil 2425.00mil 24.00mil 14.00mil 0.0000 12.00mil "" "thermal(0X,1X)"]
|
||||
Via[1075.00mil 2000.00mil 24.00mil 14.00mil 0.0000 12.00mil "" "thermal(0X,1X)"]
|
||||
Via[1100.00mil 2850.00mil 24.00mil 14.00mil 0.0000 12.00mil "" "thermal(0X,1X)"]
|
||||
|
||||
Element["" "" "" "" 500.00mil 250.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 3050.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" "thermal(1X)"]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" "thermal(0X,1X)"]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 250.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2950.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" "thermal(1X)"]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 250.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2850.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 350.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2750.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 450.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2650.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 550.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2550.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 650.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2450.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 750.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2350.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 850.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2250.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 950.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2150.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 1050.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 2050.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 1150.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1800.00mil 1950.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 1250.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 3050.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 500.00mil 1350.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2950.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" "thermal(1X)"]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 350.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2850.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 450.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2750.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 550.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2650.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 650.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2550.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 750.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2450.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 850.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2350.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 950.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2250.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 1050.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2150.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 600.00mil 1150.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 2050.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" "thermal(1X)"]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 350.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 2100.00mil 1950.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 450.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 3050.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 550.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 3050.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 650.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2950.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 750.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2850.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 850.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2750.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 950.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2650.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 1050.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2550.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" "thermal(0X,1X,6X)"]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 1150.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2450.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 1250.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2350.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 800.00mil 1350.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2250.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 250.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2150.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 350.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 2050.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 450.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 1950.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 550.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 3150.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 650.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 3150.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 750.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2950.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 850.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2850.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 950.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2750.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 1050.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2650.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 900.00mil 1150.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2550.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 60.00mil 10.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 400.00mil 300.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2450.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 54.00mil 16.00mil 60.00mil 33.00mil "1" "1" "thermal(1X)"]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 300.00mil 300.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2350.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 54.00mil 16.00mil 60.00mil 33.00mil "1" "1" "thermal(1X)"]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 400.00mil 1300.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2250.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 54.00mil 16.00mil 60.00mil 33.00mil "1" "1" "thermal(1X)"]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 400.00mil 900.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2150.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 54.00mil 16.00mil 60.00mil 33.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 300.00mil 900.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 2050.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 54.00mil 16.00mil 60.00mil 33.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 300.00mil 1300.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 1950.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 54.00mil 16.00mil 60.00mil 33.00mil "1" "1" "thermal(1X)"]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 400.00mil 700.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1500.00mil 1850.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 54.00mil 16.00mil 60.00mil 33.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "" "" "" 300.00mil 700.00mil 0.0000 0.0000 0 100 ""]
|
||||
Element["" "" "" "" 1200.00mil 1850.00mil 0.0000 0.0000 0 100 ""]
|
||||
(
|
||||
Pin[0.0000 0.0000 54.00mil 16.00mil 60.00mil 33.00mil "1" "1" ""]
|
||||
Pin[0.0000 0.0000 60.00mil 16.00mil 66.00mil 38.00mil "1" "1" ""]
|
||||
|
||||
)
|
||||
|
||||
Element["" "REF " "" "" 300.00mil 500.00mil -66.14mil 0.0000 1 100 ""]
|
||||
Element["" "" "" "" 975.00mil 2100.00mil -7.0303mm -1.9405mm 0 100 ""]
|
||||
(
|
||||
Pad[-5.41mil 40.84mil 5.41mil 40.84mil 46.25mil 20.00mil 54.25mil "" "1" "square"]
|
||||
Pad[-5.41mil -40.84mil 5.41mil -40.84mil 46.25mil 20.00mil 54.25mil "" "2" "square"]
|
||||
ElementLine [-28.93mil -10.28mil -28.93mil 10.28mil 4.72mil]
|
||||
ElementLine [28.93mil -10.28mil 28.93mil 10.28mil 4.72mil]
|
||||
Pin[0.0000 -175.00mil 60.00mil 10.00mil 66.00mil 38.00mil "" "1" ""]
|
||||
Pin[0.0000 175.00mil 60.00mil 10.00mil 66.00mil 38.00mil "" "1" "thermal(0X,1X)"]
|
||||
Pad[0.0000 -40.00mil 0.0000 -39.00mil 50.00mil 20.00mil 56.00mil "" "1" "square"]
|
||||
Pad[0.0000 40.00mil 0.0000 41.00mil 50.00mil 20.00mil 56.00mil "" "2" "square,edge2"]
|
||||
ElementLine [40.00mil -85.00mil 40.00mil 105.00mil 10.00mil]
|
||||
ElementLine [-40.00mil -85.00mil -40.00mil 105.00mil 10.00mil]
|
||||
|
||||
)
|
||||
|
||||
Element["" "REF " "" "" 400.00mil 500.00mil -66.14mil 0.0000 1 100 ""]
|
||||
Element["" "" "" "" 975.00mil 2550.00mil 6.3047mm 21.5545mm 0 100 ""]
|
||||
(
|
||||
Pad[-5.41mil 40.84mil 5.41mil 40.84mil 46.25mil 20.00mil 54.25mil "" "1" "square"]
|
||||
Pad[-5.41mil -40.84mil 5.41mil -40.84mil 46.25mil 20.00mil 54.25mil "" "2" "square"]
|
||||
ElementLine [-28.93mil -10.28mil -28.93mil 10.28mil 4.72mil]
|
||||
ElementLine [28.93mil -10.28mil 28.93mil 10.28mil 4.72mil]
|
||||
Pin[0.0000 -175.00mil 60.00mil 10.00mil 66.00mil 38.00mil "" "1" ""]
|
||||
Pin[0.0000 175.00mil 60.00mil 10.00mil 66.00mil 38.00mil "" "1" "thermal(0X,1X)"]
|
||||
Pad[0.0000 -40.00mil 0.0000 -39.00mil 50.00mil 20.00mil 56.00mil "" "1" "square"]
|
||||
Pad[0.0000 40.00mil 0.0000 41.00mil 50.00mil 20.00mil 56.00mil "" "2" "square,edge2"]
|
||||
ElementLine [40.00mil -85.00mil 40.00mil 105.00mil 10.00mil]
|
||||
ElementLine [-40.00mil -85.00mil -40.00mil 105.00mil 10.00mil]
|
||||
|
||||
)
|
||||
|
||||
Element["" "REF " "" "" 400.00mil 1100.00mil -66.14mil 0.0000 1 100 ""]
|
||||
Element["" "" "" "" 975.00mil 3000.00mil 1.2247mm -0.2768mm 0 100 ""]
|
||||
(
|
||||
Pad[-5.41mil 40.84mil 5.41mil 40.84mil 46.25mil 20.00mil 54.25mil "" "1" "square"]
|
||||
Pad[-5.41mil -40.84mil 5.41mil -40.84mil 46.25mil 20.00mil 54.25mil "" "2" "square"]
|
||||
ElementLine [-28.93mil -10.28mil -28.93mil 10.28mil 4.72mil]
|
||||
ElementLine [28.93mil -10.28mil 28.93mil 10.28mil 4.72mil]
|
||||
Pin[0.0000 -175.00mil 60.00mil 10.00mil 66.00mil 38.00mil "" "1" ""]
|
||||
Pin[0.0000 175.00mil 60.00mil 10.00mil 66.00mil 38.00mil "" "1" "thermal(0X,1X)"]
|
||||
Pad[0.0000 -40.00mil 0.0000 -39.00mil 50.00mil 20.00mil 56.00mil "" "1" "square"]
|
||||
Pad[0.0000 40.00mil 0.0000 41.00mil 50.00mil 20.00mil 56.00mil "" "2" "square,edge2"]
|
||||
ElementLine [40.00mil -85.00mil 40.00mil 105.00mil 10.00mil]
|
||||
ElementLine [-40.00mil -85.00mil -40.00mil 105.00mil 10.00mil]
|
||||
|
||||
)
|
||||
|
||||
Element["" "REF " "" "" 300.00mil 1100.00mil -66.14mil 0.0000 1 100 ""]
|
||||
Element["" "" "" "" 975.00mil 1650.00mil -7.0303mm -1.9405mm 0 100 ""]
|
||||
(
|
||||
Pad[-5.41mil 40.84mil 5.41mil 40.84mil 46.25mil 20.00mil 54.25mil "" "1" "square"]
|
||||
Pad[-5.41mil -40.84mil 5.41mil -40.84mil 46.25mil 20.00mil 54.25mil "" "2" "square"]
|
||||
ElementLine [-28.93mil -10.28mil -28.93mil 10.28mil 4.72mil]
|
||||
ElementLine [28.93mil -10.28mil 28.93mil 10.28mil 4.72mil]
|
||||
Pin[0.0000 -175.00mil 60.00mil 10.00mil 66.00mil 38.00mil "" "1" "thermal(0X,1X)"]
|
||||
Pin[0.0000 175.00mil 60.00mil 10.00mil 66.00mil 38.00mil "" "1" ""]
|
||||
Pad[0.0000 -40.00mil 0.0000 -39.00mil 50.00mil 20.00mil 56.00mil "" "1" "square"]
|
||||
Pad[0.0000 40.00mil 0.0000 41.00mil 50.00mil 20.00mil 56.00mil "" "2" "square,edge2"]
|
||||
ElementLine [40.00mil -85.00mil 40.00mil 105.00mil 10.00mil]
|
||||
ElementLine [-40.00mil -85.00mil -40.00mil 105.00mil 10.00mil]
|
||||
|
||||
)
|
||||
Layer(1 "top" "copper")
|
||||
(
|
||||
Line[500.00mil 350.00mil 600.00mil 350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 450.00mil 600.00mil 450.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 550.00mil 600.00mil 550.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 650.00mil 600.00mil 650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 250.00mil 900.00mil 250.00mil 20.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 450.00mil 900.00mil 350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 550.00mil 900.00mil 450.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 650.00mil 900.00mil 550.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 750.00mil 900.00mil 650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 850.00mil 900.00mil 750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 950.00mil 900.00mil 850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 1350.00mil 850.00mil 1350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[850.00mil 1350.00mil 900.00mil 1300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[900.00mil 1300.00mil 900.00mil 1150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 1150.00mil 900.00mil 1050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[800.00mil 1050.00mil 900.00mil 950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[600.00mil 1250.00mil 600.00mil 1150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 1250.00mil 550.00mil 1200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 1200.00mil 550.00mil 1135.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 1135.00mil 600.00mil 1085.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[600.00mil 1085.00mil 600.00mil 1050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 1150.00mil 500.00mil 1120.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 1120.00mil 550.00mil 1070.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 1070.00mil 550.00mil 1035.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 1035.00mil 600.00mil 985.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[600.00mil 985.00mil 600.00mil 950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 1050.00mil 500.00mil 1030.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 1030.00mil 550.00mil 980.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 980.00mil 550.00mil 935.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 935.00mil 600.00mil 885.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[600.00mil 885.00mil 600.00mil 850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 950.00mil 500.00mil 940.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 940.00mil 550.00mil 890.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 890.00mil 550.00mil 835.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 835.00mil 600.00mil 785.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[600.00mil 785.00mil 600.00mil 750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 1350.00mil 600.00mil 1250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 600.00mil 650.00mil 600.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[650.00mil 600.00mil 700.00mil 550.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[700.00mil 550.00mil 700.00mil 450.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[700.00mil 450.00mil 800.00mil 350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[600.00mil 250.00mil 350.00mil 250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[350.00mil 250.00mil 300.00mil 300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 750.00mil 350.00mil 750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[350.00mil 750.00mil 300.00mil 700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 1350.00mil 350.00mil 1350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[350.00mil 1350.00mil 300.00mil 1300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[500.00mil 850.00mil 450.00mil 850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[450.00mil 850.00mil 400.00mil 900.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[300.00mil 875.00mil 375.00mil 800.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[375.00mil 800.00mil 525.00mil 800.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[525.00mil 800.00mil 550.00mil 775.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 775.00mil 550.00mil 725.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[550.00mil 725.00mil 575.00mil 700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[575.00mil 700.00mil 650.00mil 700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[650.00mil 700.00mil 725.00mil 775.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[725.00mil 775.00mil 725.00mil 1175.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[725.00mil 1175.00mil 800.00mil 1250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[300.00mil 300.00mil 300.00mil 459.16mil 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 250.00mil 400.00mil 459.16mil 10.00mil 14.00mil "clearline"]
|
||||
Line[300.00mil 540.84mil 300.00mil 700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 700.00mil 400.00mil 540.84mil 10.00mil 14.00mil "clearline"]
|
||||
Line[300.00mil 875.00mil 300.00mil 26.9027mm 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 900.00mil 400.00mil 26.9027mm 10.00mil 14.00mil "clearline"]
|
||||
Line[300.00mil 1300.00mil 300.00mil 28.9773mm 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 1350.00mil 400.00mil 28.9773mm 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2950.00mil 2050.00mil 2950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2050.00mil 2950.00mil 1850.00mil 3150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1850.00mil 3150.00mil 1500.00mil 3150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2850.00mil 2050.00mil 2850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2050.00mil 2850.00mil 1900.00mil 3000.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1900.00mil 3000.00mil 1700.00mil 3000.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 3000.00mil 1650.00mil 3050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 3050.00mil 1500.00mil 3050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2750.00mil 2050.00mil 2750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2050.00mil 2750.00mil 1900.00mil 2900.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1900.00mil 2900.00mil 1700.00mil 2900.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 2900.00mil 1650.00mil 2950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2950.00mil 1500.00mil 2950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2650.00mil 2050.00mil 2650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2050.00mil 2650.00mil 1900.00mil 2800.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1900.00mil 2800.00mil 1700.00mil 2800.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 2800.00mil 1650.00mil 2850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2850.00mil 1500.00mil 2850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2550.00mil 2050.00mil 2550.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2050.00mil 2550.00mil 1900.00mil 2700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1900.00mil 2700.00mil 1700.00mil 2700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 2700.00mil 1650.00mil 2750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2750.00mil 1500.00mil 2750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2450.00mil 2050.00mil 2450.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2050.00mil 2450.00mil 1900.00mil 2600.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1900.00mil 2600.00mil 1700.00mil 2600.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 2600.00mil 1650.00mil 2650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2650.00mil 1500.00mil 2650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 1950.00mil 1750.00mil 1950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1750.00mil 1950.00mil 1550.00mil 2150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1550.00mil 2150.00mil 1500.00mil 2150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2050.00mil 2350.00mil 1900.00mil 2500.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1900.00mil 2500.00mil 1400.00mil 2500.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2500.00mil 1350.00mil 2550.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1350.00mil 2550.00mil 1200.00mil 2550.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2350.00mil 2050.00mil 2350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1500.00mil 2450.00mil 1675.00mil 2450.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1675.00mil 2450.00mil 1725.00mil 2400.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1725.00mil 2400.00mil 1875.00mil 2400.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1875.00mil 2400.00mil 2025.00mil 2250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2250.00mil 2025.00mil 2250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2025.00mil 2150.00mil 1875.00mil 2300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1875.00mil 2300.00mil 1725.00mil 2300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1725.00mil 2300.00mil 1675.00mil 2350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1675.00mil 2350.00mil 1500.00mil 2350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2025.00mil 2150.00mil 2100.00mil 2150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1500.00mil 2250.00mil 1675.00mil 2250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1675.00mil 2250.00mil 1725.00mil 2200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1725.00mil 2200.00mil 1875.00mil 2200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1875.00mil 2200.00mil 2025.00mil 2050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 2050.00mil 2025.00mil 2050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 2825.00mil 1100.00mil 2700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1100.00mil 2700.00mil 1100.00mil 2350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1100.00mil 2350.00mil 1150.00mil 2300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1150.00mil 2300.00mil 1225.00mil 2300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1225.00mil 2300.00mil 1325.00mil 2200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1325.00mil 2200.00mil 1400.00mil 2125.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1475.00mil 2050.00mil 1500.00mil 2050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 2375.00mil 1150.00mil 2200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1150.00mil 2200.00mil 1250.00mil 2200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1250.00mil 2200.00mil 1300.00mil 2150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1300.00mil 2150.00mil 1300.00mil 2125.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1475.00mil 1950.00mil 1500.00mil 1950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 1925.00mil 1025.00mil 1925.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1025.00mil 1925.00mil 1100.00mil 1850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1100.00mil 1850.00mil 1200.00mil 1850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 1825.00mil 1025.00mil 1825.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1025.00mil 1825.00mil 1075.00mil 1775.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1075.00mil 1775.00mil 1275.00mil 1775.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1275.00mil 1775.00mil 1350.00mil 1850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1350.00mil 1850.00mil 1500.00mil 1850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 3175.00mil 975.00mil 3040.50mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 2960.50mil 975.00mil 2825.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 2725.00mil 975.00mil 2590.50mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 2510.50mil 975.00mil 2375.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 2275.00mil 975.00mil 2140.50mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 2060.50mil 975.00mil 1925.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 1825.00mil 975.00mil 1690.50mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 1610.50mil 975.00mil 1475.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2125.00mil 1475.00mil 2050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1300.00mil 2125.00mil 1475.00mil 1950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1725.00mil 2100.00mil 1875.00mil 2100.00mil 12.00mil 14.00mil "clearline"]
|
||||
Line[1875.00mil 2100.00mil 2025.00mil 1950.00mil 12.00mil 14.00mil "clearline"]
|
||||
Line[2025.00mil 1950.00mil 2100.00mil 1950.00mil 12.00mil 14.00mil "clearline"]
|
||||
Line[1725.00mil 2100.00mil 1625.00mil 2200.00mil 12.00mil 14.00mil "clearline"]
|
||||
Line[1625.00mil 2200.00mil 1450.00mil 2200.00mil 12.00mil 14.00mil "clearline"]
|
||||
Line[1450.00mil 2200.00mil 1375.00mil 2275.00mil 12.00mil 14.00mil "clearline"]
|
||||
Line[1375.00mil 2275.00mil 1375.00mil 2325.00mil 12.00mil 14.00mil "clearline"]
|
||||
Line[1375.00mil 2325.00mil 1250.00mil 2450.00mil 12.00mil 14.00mil "clearline"]
|
||||
Line[1250.00mil 2450.00mil 1200.00mil 2450.00mil 12.00mil 14.00mil "clearline"]
|
||||
Polygon("clearpoly,fullpoly")
|
||||
(
|
||||
[925.00mil 1425.00mil] [1600.00mil 1425.00mil] [1625.00mil 1450.00mil] [1625.00mil 1850.00mil] [1650.00mil 1875.00mil]
|
||||
[2150.00mil 1875.00mil] [2175.00mil 1900.00mil] [2175.00mil 3225.00mil] [2150.00mil 3250.00mil] [925.00mil 3250.00mil]
|
||||
[900.00mil 3225.00mil] [900.00mil 1450.00mil]
|
||||
)
|
||||
)
|
||||
Layer(2 "ground" "copper")
|
||||
(
|
||||
Polygon("clearpoly")
|
||||
Line[1250.00mil 1950.00mil 1200.00mil 1950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2100.00mil 1250.00mil 1950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1600.00mil 2100.00mil 1400.00mil 2100.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2050.00mil 1600.00mil 2100.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2050.00mil 1650.00mil 2050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1250.00mil 2050.00mil 1200.00mil 2050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2200.00mil 1250.00mil 2050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1600.00mil 2200.00mil 1400.00mil 2200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2150.00mil 1600.00mil 2200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2150.00mil 1650.00mil 2150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1250.00mil 2150.00mil 1200.00mil 2150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2300.00mil 1250.00mil 2150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1600.00mil 2300.00mil 1400.00mil 2300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1250.00mil 2250.00mil 1200.00mil 2250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2400.00mil 1250.00mil 2250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1600.00mil 2400.00mil 1400.00mil 2400.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2350.00mil 1600.00mil 2400.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2350.00mil 1650.00mil 2350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2450.00mil 1800.00mil 2450.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1600.00mil 2500.00mil 1650.00mil 2450.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2500.00mil 1600.00mil 2500.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1250.00mil 2350.00mil 1400.00mil 2500.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1200.00mil 2350.00mil 1250.00mil 2350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1350.00mil 2650.00mil 1200.00mil 2650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2600.00mil 1350.00mil 2650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1600.00mil 2600.00mil 1400.00mil 2600.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2550.00mil 1600.00mil 2600.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2550.00mil 1650.00mil 2550.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1350.00mil 2750.00mil 1200.00mil 2750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2700.00mil 1350.00mil 2750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2700.00mil 1400.00mil 2700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 2650.00mil 1650.00mil 2700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2650.00mil 1700.00mil 2650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1350.00mil 2850.00mil 1200.00mil 2850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2800.00mil 1350.00mil 2850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2800.00mil 1400.00mil 2800.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 2750.00mil 1650.00mil 2800.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2750.00mil 1700.00mil 2750.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1350.00mil 2950.00mil 1200.00mil 2950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 2900.00mil 1350.00mil 2950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2900.00mil 1400.00mil 2900.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 2850.00mil 1650.00mil 2900.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2850.00mil 1700.00mil 2850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1350.00mil 3050.00mil 1200.00mil 3050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 3000.00mil 1350.00mil 3050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 3000.00mil 1400.00mil 3000.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1700.00mil 2950.00mil 1650.00mil 3000.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2950.00mil 1700.00mil 2950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1350.00mil 3150.00mil 1200.00mil 3150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1400.00mil 3100.00mil 1350.00mil 3150.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1725.00mil 3100.00mil 1400.00mil 3100.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1950.00mil 3050.00mil 1875.00mil 3125.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2100.00mil 3050.00mil 1950.00mil 3050.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 2250.00mil 1600.00mil 2300.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1800.00mil 2250.00mil 1650.00mil 2250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1875.00mil 3125.00mil 1750.00mil 3125.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1750.00mil 3125.00mil 1725.00mil 3100.00mil 10.00mil 14.00mil "clearline"]
|
||||
Polygon("clearpoly,fullpoly")
|
||||
(
|
||||
[250.00mil 200.00mil] [950.00mil 200.00mil] [975.00mil 225.00mil] [975.00mil 1400.00mil] [950.00mil 1425.00mil]
|
||||
[250.00mil 1425.00mil] [225.00mil 1400.00mil] [225.00mil 225.00mil]
|
||||
[925.00mil 1425.00mil] [1600.00mil 1425.00mil] [1625.00mil 1450.00mil] [1625.00mil 1850.00mil] [1650.00mil 1875.00mil]
|
||||
[2150.00mil 1875.00mil] [2175.00mil 1900.00mil] [2175.00mil 3225.00mil] [2150.00mil 3250.00mil] [925.00mil 3250.00mil]
|
||||
[900.00mil 3225.00mil] [900.00mil 1450.00mil]
|
||||
)
|
||||
)
|
||||
Layer(3 "signal2" "copper")
|
||||
|
@ -1225,14 +1327,18 @@ Layer(6 "bottom" "copper")
|
|||
)
|
||||
Layer(7 "outline" "copper")
|
||||
(
|
||||
Line[950.00mil 200.00mil 975.00mil 225.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 225.00mil 975.00mil 1400.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[975.00mil 1400.00mil 950.00mil 1425.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[950.00mil 1425.00mil 250.00mil 1425.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[250.00mil 1425.00mil 225.00mil 1400.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[225.00mil 1400.00mil 225.00mil 225.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[225.00mil 225.00mil 250.00mil 200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[250.00mil 200.00mil 950.00mil 200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[900.00mil 1450.00mil 900.00mil 3225.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[900.00mil 3225.00mil 925.00mil 3250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[925.00mil 3250.00mil 2150.00mil 3250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2150.00mil 3250.00mil 2175.00mil 3225.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2175.00mil 3225.00mil 2175.00mil 1900.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2175.00mil 1900.00mil 2150.00mil 1875.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[2150.00mil 1875.00mil 1650.00mil 1875.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1650.00mil 1875.00mil 1625.00mil 1850.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1625.00mil 1850.00mil 1625.00mil 1450.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1625.00mil 1450.00mil 1600.00mil 1425.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1600.00mil 1425.00mil 925.00mil 1425.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[900.00mil 1450.00mil 925.00mil 1425.00mil 10.00mil 14.00mil "clearline"]
|
||||
)
|
||||
Layer(8 "spare" "copper")
|
||||
(
|
||||
|
@ -1242,20 +1348,29 @@ Layer(9 "bottom silk" "silk")
|
|||
)
|
||||
Layer(10 "top silk" "silk")
|
||||
(
|
||||
Line[300.00mil 425.00mil 300.00mil 350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[300.00mil 575.00mil 300.00mil 650.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 575.00mil 400.00mil 625.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[300.00mil 1025.00mil 300.00mil 950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[300.00mil 1175.00mil 300.00mil 1250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 1025.00mil 400.00mil 950.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 1175.00mil 400.00mil 1250.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[675.00mil 225.00mil 650.00mil 225.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[725.00mil 225.00mil 750.00mil 225.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[525.00mil 1400.00mil 775.00mil 1400.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[400.00mil 425.00mil 400.00mil 350.00mil 10.00mil 14.00mil "clearline"]
|
||||
Arc[700.00mil 225.00mil 25.00mil 25.00mil 10.00mil 14.00mil 0.000000 90.000000 "clearline"]
|
||||
Arc[700.00mil 225.00mil 25.00mil 25.00mil 10.00mil 14.00mil 90.000000 90.000000 "clearline"]
|
||||
Text[715.00mil 525.00mil 3 94 "GAL20V8 ADAPTER" "clearline"]
|
||||
Text[310.00mil 1350.00mil 0 94 "4k7" "clearline"]
|
||||
Text[270.00mil 210.00mil 0 94 "4k7" "clearline"]
|
||||
Line[2075.00mil 1900.00mil 2000.00mil 1900.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1900.00mil 1900.00mil 1825.00mil 1900.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1825.00mil 3100.00mil 2075.00mil 3100.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1150.00mil 1575.00mil 1550.00mil 1575.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1550.00mil 1575.00mil 1575.00mil 1600.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1575.00mil 1600.00mil 1575.00mil 3200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1575.00mil 3200.00mil 1550.00mil 3225.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1125.00mil 1600.00mil 1150.00mil 1575.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1125.00mil 1700.00mil 1175.00mil 1700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1175.00mil 1700.00mil 1175.00mil 1525.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1125.00mil 1525.00mil 1125.00mil 1700.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1175.00mil 1525.00mil 1125.00mil 1525.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1550.00mil 3225.00mil 1150.00mil 3225.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1150.00mil 3225.00mil 1125.00mil 3200.00mil 10.00mil 14.00mil "clearline"]
|
||||
Line[1125.00mil 3200.00mil 1125.00mil 1525.00mil 10.00mil 14.00mil "clearline"]
|
||||
Arc[1950.00mil 1900.00mil 50.00mil 50.00mil 10.00mil 14.00mil 180.000000 -90.000000 "clearline"]
|
||||
Arc[1950.00mil 1900.00mil 50.00mil 50.00mil 10.00mil 14.00mil 90.000000 -90.000000 "clearline"]
|
||||
Text[1025.00mil 2600.00mil 1 94 "4k7" "clearline"]
|
||||
Text[1025.00mil 3050.00mil 1 94 "4k7" "clearline"]
|
||||
Text[1025.00mil 2150.00mil 1 94 "4k7" "clearline"]
|
||||
Text[1025.00mil 1700.00mil 1 94 "4k7" "clearline"]
|
||||
Text[1800.00mil 3175.00mil 0 94 "-= olin =-" "clearline"]
|
||||
Text[1700.00mil 3125.00mil 0 94 "RomBor 7/2021" "clearline"]
|
||||
Text[1915.00mil 2830.00mil 1 116 "26V12 -> 22V10 r1" "clearline"]
|
||||
Text[1325.00mil 2475.00mil 1 94 "ZIF 28P Narrow" "clearline"]
|
||||
)
|
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 158 KiB |
|
@ -2,6 +2,8 @@
|
|||
#define _SERIAL_PORT_H_
|
||||
|
||||
|
||||
char guessedSerialDevice[512] = {0};
|
||||
|
||||
#ifdef _USE_WIN_API_
|
||||
|
||||
#include <windows.h>
|
||||
|
@ -10,11 +12,61 @@
|
|||
#define DEFAULT_SERIAL_DEVICE_NAME "COM1"
|
||||
#define INVALID_HANDLE INVALID_HANDLE_VALUE
|
||||
|
||||
#ifdef NO_CLOSE
|
||||
static SerialDeviceHandle serH = INVALID_HANDLE;
|
||||
#endif
|
||||
|
||||
// ideas: https://stackoverflow.com/questions/1388871/how-do-i-get-a-list-of-available-serial-ports-in-win32
|
||||
static void serialDeviceGuessName(char** deviceName) {
|
||||
char buf[64 * 1024] = {0};
|
||||
int size = QueryDosDevice(NULL, buf, 64 * 1024);
|
||||
int topComNum = 0;
|
||||
|
||||
// buffer was filled in
|
||||
if (size > 0) {
|
||||
char* text = buf;
|
||||
int pos = 0;
|
||||
int start = 0;
|
||||
|
||||
// search the received buffer for COM string
|
||||
while (pos < size) {
|
||||
int nameLen;
|
||||
start = pos;
|
||||
// find the string terminator
|
||||
while(pos < size && buf[pos] != 0) {
|
||||
pos++;
|
||||
}
|
||||
nameLen = pos - start;
|
||||
// COM port found
|
||||
if (nameLen >= 4 && nameLen <=6 && 0 == strncmp(text, "COM", 3) && text[3] >= '0' && text[3] <= '9') {
|
||||
int comNum = atoi(text + 3);
|
||||
if (comNum > topComNum) {
|
||||
topComNum = comNum;
|
||||
strcpy(guessedSerialDevice, text);
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
text = &buf[pos];
|
||||
}
|
||||
|
||||
// if we have found a COM port then pass it back as the result
|
||||
if (topComNum > 0) {
|
||||
*deviceName = guessedSerialDevice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.xanthium.in/Serial-Port-Programming-using-Win32-API
|
||||
|
||||
static inline SerialDeviceHandle serialDeviceOpen(char* deviceName) {
|
||||
SerialDeviceHandle h;
|
||||
|
||||
#ifdef NO_CLOSE
|
||||
if (serH != INVALID_HANDLE) {
|
||||
return serH;
|
||||
}
|
||||
#endif
|
||||
|
||||
h = CreateFile(
|
||||
deviceName, //port name
|
||||
GENERIC_READ | GENERIC_WRITE, //Read/Write
|
||||
|
@ -67,7 +119,9 @@ static inline SerialDeviceHandle serialDeviceOpen(char* deviceName) {
|
|||
}
|
||||
//ensure no leftover bytes exist on the serial line
|
||||
result = PurgeComm(h, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
|
||||
|
||||
#ifdef NO_CLOSE
|
||||
serH = h;
|
||||
#endif
|
||||
return h;
|
||||
} else {
|
||||
return INVALID_HANDLE;
|
||||
|
@ -100,7 +154,9 @@ void serialDeviceCheckName(char* name, int maxSize) {
|
|||
}
|
||||
|
||||
static inline void serialDeviceClose(SerialDeviceHandle deviceHandle) {
|
||||
#ifndef NO_CLOSE
|
||||
CloseHandle(deviceHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int serialDeviceWrite(SerialDeviceHandle deviceHandle, char* buffer, int bytesToWrite) {
|
||||
|
@ -128,11 +184,58 @@ static inline int serialDeviceRead(SerialDeviceHandle deviceHandle, char* buffer
|
|||
#define DEFAULT_SERIAL_DEVICE_NAME "/dev/ttyUSB0"
|
||||
|
||||
#define INVALID_HANDLE -1
|
||||
|
||||
#ifdef NO_CLOSE
|
||||
static SerialDeviceHandle serH = INVALID_HANDLE;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _OSX_
|
||||
#define CHECK_SERIAL() (text != NULL)
|
||||
#define LIST_DEVICES "ls -1 /dev/tty.usb* /dev/tty.wchusb* 2>/dev/null"
|
||||
#else
|
||||
#define CHECK_SERIAL() (text != NULL && 0 == strncmp(text + 18, "usb-", 4))
|
||||
#define LIST_DEVICES "ls -1 /dev/serial/by-id/* 2>/dev/null"
|
||||
#endif
|
||||
|
||||
// ideas: https://unix.stackexchange.com/questions/647235/debian-how-to-identify-usb-devices-with-similar-dev-tty-file
|
||||
// https://pubs.opengroup.org/onlinepubs/009696799/functions/popen.html
|
||||
static void serialDeviceGuessName(char** deviceName) {
|
||||
int i;
|
||||
char text[512];
|
||||
int topTtyNum = 0;
|
||||
|
||||
FILE* f = popen(LIST_DEVICES, "r");
|
||||
if (f == NULL) {
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
while (fgets(text, 512, f) != NULL) {
|
||||
// filer out non USB devices and prioritise those with Arduino name
|
||||
if (CHECK_SERIAL()) {
|
||||
int ttyNum = i;
|
||||
int textLen = strlen(text);
|
||||
// prefer Arduino over generic USB serial ports (does not work on OSX)
|
||||
if (textLen > 29 && 0 == strncmp(text + 18, "usb-Arduino", 11)) {
|
||||
ttyNum += 1000;
|
||||
}
|
||||
if (ttyNum > topTtyNum) {
|
||||
topTtyNum = ttyNum;
|
||||
strcpy(guessedSerialDevice, text);
|
||||
//strip the new-line trailing markers
|
||||
if (guessedSerialDevice[textLen - 1] == '\n' || guessedSerialDevice[textLen - 1] == '\r') {
|
||||
guessedSerialDevice[textLen - 1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
pclose(f);
|
||||
|
||||
if (topTtyNum > 0) {
|
||||
*deviceName = guessedSerialDevice;
|
||||
}
|
||||
}
|
||||
|
||||
static inline SerialDeviceHandle serialDeviceOpen(char* deviceName) {
|
||||
|
||||
SerialDeviceHandle h;
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
# Be careful modifying this file: line ranges from it are included in docs/jtag/as.rst.
|
||||
|
||||
import enum
|
||||
from bitarray import bitarray
|
||||
|
||||
|
||||
|
||||
__all__ = ['ATF15xxInstr', 'ATF1502ASDevice', 'ATF1504ASDevice', 'ATF1508ASDevice']
|
||||
|
||||
|
||||
class ATF15xxInstr(enum.IntEnum):
|
||||
EXTEST = 0x000
|
||||
SAMPLE = 0x055
|
||||
IDCODE = 0x059
|
||||
ISC_READ_UES = 0x270
|
||||
ISC_CONFIG = 0x280
|
||||
ISC_READ = 0x28c
|
||||
ISC_DATA = 0x290
|
||||
ISC_PROGRAM_ERASE = 0x29e
|
||||
ISC_ADDRESS = 0x2a1
|
||||
ISC_LATCH_ERASE = 0x2b3
|
||||
ISC_UNKNOWN = 0x2bf
|
||||
BYPASS = 0x3ff
|
||||
|
||||
|
||||
class ATF15xxDevice:
|
||||
idcode = None # int
|
||||
|
||||
fuse_count = None # int
|
||||
data_width = None # dict(range/tuple,range)
|
||||
|
||||
@classmethod
|
||||
def word_size(cls, svf_row):
|
||||
for svf_rows, svf_cols in cls.data_width.items():
|
||||
if svf_row in svf_rows:
|
||||
return len(svf_cols)
|
||||
assert False
|
||||
|
||||
@staticmethod
|
||||
def jed_to_svf_coords(jed_index):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def jed_to_svf(cls, jed_bits):
|
||||
svf_bits = {}
|
||||
for jed_index, jed_bit in enumerate(jed_bits):
|
||||
svf_index = cls.jed_to_svf_coords(jed_index)
|
||||
if svf_index is None: continue
|
||||
svf_row, svf_col = svf_index
|
||||
if svf_row not in svf_bits:
|
||||
svf_bits[svf_row] = bitarray(cls.word_size(svf_row))
|
||||
svf_bits[svf_row].setall(1)
|
||||
svf_bits[svf_row][svf_col] = jed_bit
|
||||
return svf_bits
|
||||
|
||||
@staticmethod
|
||||
def svf_to_jed_coords(svf_row, svf_col):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def svf_to_jed(cls, svf_bits):
|
||||
jed_bits = bitarray(cls.fuse_count)
|
||||
jed_bits.setall(0)
|
||||
for svf_row, svf_word in svf_bits.items():
|
||||
for svf_col, svf_bit in enumerate(svf_word):
|
||||
jed_index = cls.svf_to_jed_coords(svf_row, svf_col)
|
||||
if jed_index is None: continue
|
||||
jed_bits[jed_index] = svf_bit
|
||||
return jed_bits
|
||||
|
||||
|
||||
class ATF1502ASDevice(ATF15xxDevice):
|
||||
idcode = 0x0150203f
|
||||
|
||||
fuse_count = 16808
|
||||
data_width = {
|
||||
range( 0, 108): range(86),
|
||||
range(128, 229): range(86),
|
||||
(256,): range(32),
|
||||
(512,): range(4),
|
||||
(768,): range(16),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def jed_to_svf_coords(jed_index):
|
||||
if jed_index in range( 0, 7680):
|
||||
return 12 + (jed_index - 0) % 96, 79 - (jed_index - 0) // 96
|
||||
if jed_index in range( 7680, 15360):
|
||||
return 128 + (jed_index - 7680) % 96, 79 - (jed_index - 7680) // 96
|
||||
if jed_index in range(15360, 16320):
|
||||
return 0 + (jed_index - 15360) // 80, 79 - (jed_index - 15360) % 80
|
||||
if jed_index in range(16320, 16720):
|
||||
return 224 + (jed_index - 16320) % 5, 79 - (jed_index - 16320) // 5
|
||||
if jed_index in range(16720, 16750):
|
||||
return 224 + (jed_index - 16320) % 5, 85 - (jed_index - 16320) // 5 + 80
|
||||
if jed_index in range(16750, 16782):
|
||||
return 256, 31 - (jed_index - 16750)
|
||||
if jed_index in range(16782, 16786):
|
||||
return 512, 3 - (jed_index - 16782)
|
||||
if jed_index in range(16786, 16802):
|
||||
return 768, 15 - (jed_index - 16786)
|
||||
if jed_index in range(16802, 16808):
|
||||
return # reserved
|
||||
assert False
|
||||
|
||||
@staticmethod
|
||||
def svf_to_jed_coords(svf_row, svf_col):
|
||||
if svf_row in range( 0, 12):
|
||||
if svf_col in range(0, 80):
|
||||
return 15360 + (svf_row - 0) * 80 + (79 - svf_col)
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range( 12, 108):
|
||||
if svf_col in range(0, 80):
|
||||
return 0 + (svf_row - 12) + (79 - svf_col) * 96
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range(128, 224):
|
||||
if svf_col in range(0, 80):
|
||||
return 7680 + (svf_row - 128) + (79 - svf_col) * 96
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range(224, 229):
|
||||
if svf_col in range(0, 80):
|
||||
return 16320 + (svf_row - 224) + (79 - svf_col) * 5
|
||||
else:
|
||||
return 16720 + (svf_row - 224) + (85 - svf_col) * 5
|
||||
if svf_row == 256:
|
||||
return 16750 + (31 - svf_col)
|
||||
if svf_row == 512:
|
||||
return 16782 + ( 3 - svf_col)
|
||||
if svf_row == 768:
|
||||
return 16786 + (15 - svf_col)
|
||||
assert False
|
||||
|
||||
|
||||
class ATF1504ASDevice(ATF15xxDevice):
|
||||
idcode = 0x0150403f
|
||||
|
||||
fuse_count = 34192
|
||||
data_width = {
|
||||
range( 0, 108): range(166),
|
||||
range(128, 233): range(166),
|
||||
(256,): range(32),
|
||||
(512,): range(4),
|
||||
(768,): range(16),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def jed_to_svf_coords(jed_index):
|
||||
if jed_index in range( 0, 15360):
|
||||
return 12 + (jed_index - 0) % 96, 165 - (jed_index - 0) // 96
|
||||
if jed_index in range(15360, 30720):
|
||||
return 128 + (jed_index - 15360) % 96, 165 - (jed_index - 15360) // 96
|
||||
if jed_index in range(30720, 32640):
|
||||
return 0 + (jed_index - 30720) // 160, 165 - (jed_index - 30720) % 160
|
||||
if jed_index in range(32640, 34134):
|
||||
return 224 + (jed_index - 32640) % 9, 165 - (jed_index - 32640) // 9
|
||||
if jed_index in range(34134, 34166):
|
||||
return 256, 31 - (jed_index - 34134)
|
||||
if jed_index in range(34166, 34170):
|
||||
return 512, 3 - (jed_index - 34166)
|
||||
if jed_index in range(34170, 34186):
|
||||
return 768, 15 - (jed_index - 34170)
|
||||
if jed_index in range(34186, 34192):
|
||||
return # reserved
|
||||
assert False
|
||||
|
||||
@staticmethod
|
||||
def svf_to_jed_coords(svf_row, svf_col):
|
||||
if svf_row in range( 0, 12):
|
||||
if svf_col in range(6, 166):
|
||||
return 30720 + (svf_row - 0) * 160 + (165 - svf_col)
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range( 12, 108):
|
||||
if svf_col in range(6, 166):
|
||||
return 0 + (svf_row - 12) + (165 - svf_col) * 96
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range(128, 224):
|
||||
if svf_col in range(6, 166):
|
||||
return 15360 + (svf_row - 128) + (165 - svf_col) * 96
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range(224, 233):
|
||||
if svf_col in range(0, 166):
|
||||
return 32640 + (svf_row - 224) + (165 - svf_col) * 9
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row == 256:
|
||||
return 34134 + (31 - svf_col)
|
||||
if svf_row == 512:
|
||||
return 34166 + ( 3 - svf_col)
|
||||
if svf_row == 768:
|
||||
return 34170 + (15 - svf_col)
|
||||
assert False
|
||||
|
||||
|
||||
class ATF1508ASDevice(ATF15xxDevice):
|
||||
idcode = 0x0150803f
|
||||
|
||||
fuse_count = 74136
|
||||
data_width = {
|
||||
range( 0, 108): range(326),
|
||||
range(128, 251): range(326),
|
||||
(256,): range(32),
|
||||
(512,): range(4),
|
||||
(768,): range(16),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def jed_to_svf_coords(jed_index):
|
||||
if jed_index in range( 0, 30720):
|
||||
return 12 + (jed_index - 0) % 96, 325 - (jed_index - 0) // 96
|
||||
if jed_index in range(30720, 61440):
|
||||
return 128 + (jed_index - 30720) % 96, 325 - (jed_index - 30720) // 96
|
||||
if jed_index in range(61440, 65280):
|
||||
return 0 + (jed_index - 61440) // 320, 325 - (jed_index - 61440) % 320
|
||||
if jed_index in range(65280, 74082):
|
||||
return 224 + (jed_index - 65280) % 27, 325 - (jed_index - 65280) // 27
|
||||
if jed_index in range(74082, 74114):
|
||||
return 256, 31 - (jed_index - 74082)
|
||||
if jed_index in range(74114, 74118):
|
||||
return 512, 3 - (jed_index - 74114)
|
||||
if jed_index in range(74118, 74134):
|
||||
return 768, 15 - (jed_index - 74118)
|
||||
if jed_index in range(74134, 74136):
|
||||
return # reserved
|
||||
assert False
|
||||
|
||||
@staticmethod
|
||||
def svf_to_jed_coords(svf_row, svf_col):
|
||||
if svf_row in range( 0, 12):
|
||||
if svf_col in range(6, 326):
|
||||
return 61440 + (svf_row - 0) * 320 + (325 - svf_col)
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range( 12, 108):
|
||||
if svf_col in range(6, 326):
|
||||
return 0 + (svf_row - 12) + (325 - svf_col) * 96
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range(128, 224):
|
||||
if svf_col in range(6, 326):
|
||||
return 30720 + (svf_row - 128) + (325 - svf_col) * 96
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row in range(224, 251):
|
||||
if svf_col in range(0, 326):
|
||||
return 65280 + (svf_row - 224) + (325 - svf_col) * 27
|
||||
else:
|
||||
return # always 1
|
||||
if svf_row == 256:
|
||||
return 74082 + (31 - svf_col)
|
||||
if svf_row == 512:
|
||||
return 74114 + ( 3 - svf_col)
|
||||
if svf_row == 768:
|
||||
return 74118 + (15 - svf_col)
|
||||
assert False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
with open('atf1502as_svf2jed.csv', 'w') as f:
|
||||
f.write('SVF ROW,SVF COL,JED\n')
|
||||
for svf_rows, svf_cols in ATF1502ASDevice.data_width.items():
|
||||
for svf_row in svf_rows:
|
||||
for svf_col in svf_cols:
|
||||
jed_index = ATF1502ASDevice.svf_to_jed_coords(svf_row, svf_col)
|
||||
if jed_index is None: jed_index = 0x7fff
|
||||
f.write('{},{},{}\n'.format(svf_row, svf_col, jed_index))
|
||||
|
||||
with open('atf1502as_jed2svf.csv', 'w') as f:
|
||||
f.write('JED,SVF ROW,SVF COL\n')
|
||||
for jed_index in range(ATF1502ASDevice.fuse_count):
|
||||
svf_index = ATF1502ASDevice.jed_to_svf_coords(jed_index)
|
||||
if svf_index is None: continue
|
||||
f.write('{},{},{}\n'.format(jed_index, *svf_index))
|
||||
|
||||
with open('atf1504as_svf2jed.csv', 'w') as f:
|
||||
f.write('SVF ROW,SVF COL,JED\n')
|
||||
for svf_rows, svf_cols in ATF1504ASDevice.data_width.items():
|
||||
for svf_row in svf_rows:
|
||||
for svf_col in svf_cols:
|
||||
jed_index = ATF1504ASDevice.svf_to_jed_coords(svf_row, svf_col)
|
||||
if jed_index is None: jed_index = 0xffff
|
||||
f.write('{},{},{}\n'.format(svf_row, svf_col, jed_index))
|
||||
|
||||
with open('atf1504as_jed2svf.csv', 'w') as f:
|
||||
f.write('JED,SVF ROW,SVF COL\n')
|
||||
for jed_index in range(ATF1504ASDevice.fuse_count):
|
||||
svf_index = ATF1504ASDevice.jed_to_svf_coords(jed_index)
|
||||
if svf_index is None: continue
|
||||
f.write('{},{},{}\n'.format(jed_index, *svf_index))
|
||||
|
||||
with open('atf1508as_svf2jed.csv', 'w') as f:
|
||||
f.write('SVF ROW,SVF COL,JED\n')
|
||||
for svf_rows, svf_cols in ATF1508ASDevice.data_width.items():
|
||||
for svf_row in svf_rows:
|
||||
for svf_col in svf_cols:
|
||||
jed_index = ATF1508ASDevice.svf_to_jed_coords(svf_row, svf_col)
|
||||
if jed_index is None: jed_index = 0x1ffff
|
||||
f.write('{},{},{}\n'.format(svf_row, svf_col, jed_index))
|
||||
|
||||
with open('atf1508as_jed2svf.csv', 'w') as f:
|
||||
f.write('JED,SVF ROW,SVF COL\n')
|
||||
for jed_index in range(ATF1508ASDevice.fuse_count):
|
||||
svf_index = ATF1508ASDevice.jed_to_svf_coords(jed_index)
|
||||
if svf_index is None: continue
|
||||
f.write('{},{},{}\n'.format(jed_index, *svf_index))
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
# specify name of your PLD design and device to run on
|
||||
APP=counter
|
||||
DEV=ATF1502AS
|
||||
PKG=PLCC44
|
||||
SPD=15
|
||||
|
||||
## compile Verilog design by yosys
|
||||
#../../../yosys/atf15xx_yosys/run_yosys.sh $APP > $APP.log
|
||||
|
||||
|
||||
## use Atmel fitter to produce .jed file
|
||||
#../../yosys/atf15xx_yosys/run_fitter.sh -d $DEV -p $PKG -s $SPD $APP -preassign keep -tdi_pullup on -tms_pullup on -output_fast off -xor_synthesis on $*
|
||||
|
||||
# convert jed to svf
|
||||
python3 ./fuseconv.py -d $DEV $APP.jed $APP.svf
|
||||
|
||||
# convert svf to xsvf
|
||||
python3 .//svf2xsvf.py $APP.svf $APP.xsvf
|
||||
|
||||
date
|
||||
echo "done!"
|
|
@ -0,0 +1,223 @@
|
|||
import argparse
|
||||
import textwrap
|
||||
from bitarray import bitarray
|
||||
|
||||
from jesd3 import JESD3Parser
|
||||
from svf import SVFParser, SVFEventHandler
|
||||
from device import *
|
||||
|
||||
|
||||
def read_jed(file):
|
||||
parser = JESD3Parser(file.read())
|
||||
parser.parse()
|
||||
return parser.fuse, parser.design_spec
|
||||
|
||||
|
||||
def write_jed(file, jed_bits, *, comment):
|
||||
assert '*' not in comment
|
||||
file.write("\x02{}*\n".format(comment))
|
||||
file.write("QF{}* F0*\n".format(len(jed_bits)))
|
||||
chunk_size = 64
|
||||
for start in range(0, len(jed_bits), chunk_size):
|
||||
file.write("L{:05d} {}*\n".format(start, jed_bits[start:start+chunk_size].to01()))
|
||||
file.write("\x030000\n")
|
||||
|
||||
|
||||
class ATFSVFEventHandler(SVFEventHandler):
|
||||
def ignored(self, *args, **kwargs):
|
||||
pass
|
||||
svf_frequency = ignored
|
||||
svf_trst = ignored
|
||||
svf_state = ignored
|
||||
svf_endir = ignored
|
||||
svf_enddr = ignored
|
||||
svf_hir = ignored
|
||||
svf_sir = ignored
|
||||
svf_tir = ignored
|
||||
svf_hdr = ignored
|
||||
svf_sdr = ignored
|
||||
svf_tdr = ignored
|
||||
svf_runtest = ignored
|
||||
svf_piomap = ignored
|
||||
svf_pio = ignored
|
||||
|
||||
def __init__(self):
|
||||
self.ir = None
|
||||
self.erase = False
|
||||
self.addr = 0
|
||||
self.data = b''
|
||||
self.bits = {}
|
||||
|
||||
def svf_sir(self, tdi, smask, tdo, mask):
|
||||
self.ir = int.from_bytes(tdi.tobytes(), 'little')
|
||||
if self.ir == ATF15xxInstr.ISC_LATCH_ERASE:
|
||||
self.erase = True
|
||||
if self.ir == ATF15xxInstr.ISC_DATA:
|
||||
self.erase = False
|
||||
|
||||
def svf_sdr(self, tdi, smask, tdo, mask):
|
||||
if self.ir == ATF15xxInstr.ISC_ADDRESS:
|
||||
self.addr = int.from_bytes(tdi.tobytes(), 'little')
|
||||
if (self.ir & ~0x3) == ATF15xxInstr.ISC_DATA:
|
||||
self.data = tdi
|
||||
|
||||
def svf_runtest(self, run_state, run_count, run_clock, min_time, max_time, end_state):
|
||||
if not self.erase and self.ir == ATF15xxInstr.ISC_PROGRAM_ERASE:
|
||||
self.bits[self.addr] = self.data
|
||||
|
||||
|
||||
def read_svf(file):
|
||||
handler = ATFSVFEventHandler()
|
||||
parser = SVFParser(file.read(), handler)
|
||||
parser.parse_file()
|
||||
return handler.bits, ''
|
||||
|
||||
|
||||
def _bitarray_to_hex(input_bits):
|
||||
bits = bitarray(input_bits, endian="little")
|
||||
bits.bytereverse()
|
||||
bits.reverse()
|
||||
return bits.tobytes().hex()
|
||||
|
||||
|
||||
def write_svf(file, svf_bits, device, *, comment):
|
||||
# This code is kind of awful.
|
||||
def emit_header():
|
||||
for comment_line in comment.splitlines():
|
||||
file.write("// {}\n".format(comment_line))
|
||||
file.write("TRST ABSENT;\n")
|
||||
file.write("ENDIR IDLE;\n")
|
||||
file.write("ENDDR IDLE;\n")
|
||||
file.write("HDR 0;\n")
|
||||
file.write("HIR 0;\n")
|
||||
file.write("TDR 0;\n")
|
||||
file.write("TIR 0;\n")
|
||||
file.write("STATE RESET;\n")
|
||||
def emit_check_idcode(idcode):
|
||||
file.write("// Check IDCODE\n")
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.IDCODE))
|
||||
file.write("SDR 32 TDI (fffeefff)\n\tTDO ({:08x})\n\tMASK (fffeefff);\n".format(idcode))
|
||||
def emit_enable():
|
||||
file.write("// ISC enable\n")
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_CONFIG))
|
||||
file.write("SDR 10 TDI ({:03x});\n".format(0x1b9)) # magic constant?
|
||||
file.write("STATE IDLE;\n")
|
||||
def emit_disable():
|
||||
file.write("// ISC disable\n")
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_CONFIG))
|
||||
file.write("SDR 10 TDI ({:03x});\n".format(0x000))
|
||||
file.write("STATE IDLE;\n")
|
||||
def emit_unknown():
|
||||
# ATMISP does this for unknown reasons. DR seems to be just BYPASS. Removing this
|
||||
# doesn't do anything (and shouldn't do anything, since ATMISP doesn't go through RTI
|
||||
# or capture/update DR), but let's keep it for now. Vendor tools wouldn't emit SIR
|
||||
# without any reason whatsoever, right? Right??
|
||||
file.write("// ISC unknown\n")
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_UNKNOWN))
|
||||
def emit_erase():
|
||||
file.write("// ISC erase\n")
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_LATCH_ERASE))
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_PROGRAM_ERASE))
|
||||
file.write("RUNTEST IDLE 210E-3 SEC;\n")
|
||||
emit_unknown()
|
||||
def emit_program(address, data):
|
||||
file.write("// ISC program word\n")
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_ADDRESS))
|
||||
file.write("SDR 11 TDI ({:03x});\n".format(address))
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_DATA | (address >> 8)))
|
||||
file.write("SDR {} TDI ({:0{}x});\n".format(len(data),
|
||||
int(data.to01()[::-1], 2), len(data) // 4))
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_PROGRAM_ERASE))
|
||||
file.write("RUNTEST IDLE 30E-3 SEC;\n")
|
||||
emit_unknown()
|
||||
def emit_verify(address, data):
|
||||
file.write("// ISC verify word\n")
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_ADDRESS))
|
||||
file.write("SDR 11 TDI ({:03x});\n".format(address))
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_READ))
|
||||
file.write("RUNTEST IDLE 20E-3 SEC;\n")
|
||||
file.write("SIR 10 TDI ({:03x});\n".format(ATF15xxInstr.ISC_DATA | (address >> 8)))
|
||||
file.write("SDR {} TDI ({:0{}x})\n\tTDO ({:0{}x})\n\tMASK ({:0{}x});\n".format(len(data),
|
||||
int(data.to01()[::-1], 2), len(data) // 4,
|
||||
int(data.to01()[::-1], 2), len(data) // 4,
|
||||
(1 << len(data)) - 1, len(data) // 4))
|
||||
|
||||
emit_header()
|
||||
emit_check_idcode(device.idcode)
|
||||
emit_enable()
|
||||
emit_erase()
|
||||
for svf_row in svf_bits:
|
||||
emit_program(svf_row, svf_bits[svf_row])
|
||||
for svf_row in svf_bits:
|
||||
emit_verify(svf_row, svf_bits[svf_row])
|
||||
emit_disable()
|
||||
|
||||
|
||||
class ATFFileType(argparse.FileType):
|
||||
def __call__(self, value):
|
||||
file = super().__call__(value)
|
||||
filename = file.name.lower()
|
||||
if not (filename.endswith('.jed') or filename.endswith('.svf')):
|
||||
raise argparse.ArgumentTypeError('{} is not a JED or SVF file'.format(filename))
|
||||
return file
|
||||
|
||||
|
||||
def arg_parser():
|
||||
parser = argparse.ArgumentParser(description=textwrap.dedent("""
|
||||
Convert between ATF15xx JED and SVF files. The type of the file is determined by the extension
|
||||
(``.jed`` or ``.svf``, respectively).
|
||||
|
||||
If an SVF file is provided as an input, it is used to drive the JTAG programming state machine
|
||||
of a simulated device. The state machine is greatly simplified and only functions correctly
|
||||
when driven with vectors that program every non-reserved bit at least once.
|
||||
"""))
|
||||
parser.add_argument(
|
||||
'-d', '--device', metavar='DEVICE',
|
||||
choices=('ATF1502AS', 'ATF1504AS', 'ATF1508AS'), default='ATF1502AS',
|
||||
help='Select the device to use.')
|
||||
parser.add_argument(
|
||||
'input', metavar='INPUT', type=ATFFileType('r'),
|
||||
help='Read fuses from file INPUT.')
|
||||
parser.add_argument(
|
||||
'output', metavar='OUTPUT', type=ATFFileType('w'),
|
||||
help='Write fuses to file OUTPUT.')
|
||||
return parser
|
||||
|
||||
|
||||
def main():
|
||||
args = arg_parser().parse_args()
|
||||
|
||||
if args.device == 'ATF1502AS':
|
||||
device = ATF1502ASDevice
|
||||
elif args.device == 'ATF1504AS':
|
||||
device = ATF1504ASDevice
|
||||
elif args.device == 'ATF1508AS':
|
||||
device = ATF1508ASDevice
|
||||
else:
|
||||
assert False
|
||||
|
||||
jed_bits = svf_bits = None
|
||||
if args.input.name.lower().endswith('.jed'):
|
||||
jed_bits, comment = read_jed(args.input)
|
||||
if device.fuse_count != len(jed_bits):
|
||||
raise SystemExit(f"Device has {device.fuse_count} fuses, JED file "
|
||||
f"has {len(jed_bits)}; wrong --device option?")
|
||||
elif args.input.name.lower().endswith('.svf'):
|
||||
svf_bits, comment = read_svf(args.input)
|
||||
else:
|
||||
assert False
|
||||
|
||||
if args.output.name.lower().endswith('.jed'):
|
||||
if jed_bits is None:
|
||||
jed_bits = device.svf_to_jed(svf_bits)
|
||||
write_jed(args.output, jed_bits, comment=comment)
|
||||
elif args.output.name.lower().endswith('.svf'):
|
||||
if svf_bits is None:
|
||||
svf_bits = device.jed_to_svf(jed_bits)
|
||||
write_svf(args.output, svf_bits, device, comment=comment)
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,300 @@
|
|||
# Vendored from glasgow.protocol.jesd3
|
||||
|
||||
# Ref: JEDEC JESD3-C
|
||||
# Accession: G00029
|
||||
|
||||
import re
|
||||
from bitarray import bitarray
|
||||
|
||||
|
||||
__all__ = ["JESD3Parser", "JESD3ParsingError"]
|
||||
|
||||
|
||||
class JESD3ParsingError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class JESD3Lexer:
|
||||
"""
|
||||
A JESD3 (JED) lexer.
|
||||
|
||||
:type buffer: str
|
||||
:attr buffer:
|
||||
Input buffer.
|
||||
|
||||
:type position: int
|
||||
:attr position:
|
||||
Offset into buffer from which the next field will be read.
|
||||
"""
|
||||
|
||||
# This follows the JESD3-C grammar, with the exception that spaces are more permissive.
|
||||
# As described, only 0x0D is allowed in between fields, which is absurd.
|
||||
_fields = (
|
||||
(r"N", r"[ \r\n]*(.*?)"),
|
||||
(r"D", r".*?"),
|
||||
(r"QF", r"([0-9]+)"),
|
||||
(r"QP", r"([0-9]+)"),
|
||||
(r"QV", r"([0-9]+)"),
|
||||
(r"F", r"([01])"),
|
||||
(r"L", r"([0-9]+)[ \r\n]+([01 \r\n]+)"),
|
||||
(r"C", r"([0-9A-F]{4})"),
|
||||
(r"EH", r"([0-9A-F]+)"),
|
||||
(r"E", r"([01]+)"),
|
||||
(r"UA", r"([\r\n\x20-\x29\x2B-\x7E]+)"),
|
||||
(r"UH", r"([0-9A-F]+)"),
|
||||
(r"U", r"([01]+)"),
|
||||
(r"J", r"([0-9]+)[ \r\n]+([0-9]+)"),
|
||||
(r"G", r"([01])"),
|
||||
(r"X", r"([01])"),
|
||||
(r"P", r"([ \r\n]*[0-9]+)+"),
|
||||
(r"V", r"([0-9]+)[ \r\n]+([0-9BCDFHTUXZ]+)"),
|
||||
(r"S", r"([01]+)"),
|
||||
(r"R", r"([0-9A-F]{8})"),
|
||||
(r"T", r"([0-9]+)"),
|
||||
(r"A", r"([\r\n\x20-\x29\x2B-\x7E]*)([0-9]+)"),
|
||||
)
|
||||
_stx_spec_re = re.compile(r"\x02(.*?)\*[ \r\n]*", re.A|re.S)
|
||||
_stx_quirk_re = re.compile(r"\x02()[ \r\n]*", re.A|re.S)
|
||||
_etx_re = re.compile(r"\x03([0-9A-F]{4})", re.A|re.S)
|
||||
_ident_re = re.compile(r"|".join(ident for ident, args in _fields), re.A|re.S)
|
||||
_field_res = {ident: re.compile(ident + args + r"[ \r\n]*\*[ \r\n]*", re.A|re.S)
|
||||
for ident, args in _fields}
|
||||
|
||||
def __init__(self, buffer, quirk_no_design_spec=False):
|
||||
self.buffer = buffer
|
||||
self.position = 0
|
||||
self.checksum = 0
|
||||
self._state = "start"
|
||||
if quirk_no_design_spec:
|
||||
self._stx_re = self._stx_quirk_re
|
||||
else:
|
||||
self._stx_re = self._stx_spec_re
|
||||
|
||||
def line_column(self, position=None):
|
||||
"""
|
||||
Return a ``(line, column)`` tuple for the given or, if not specified, current position.
|
||||
|
||||
Both the line and the column start at 1.
|
||||
"""
|
||||
line = len(re.compile(r"\n").findall(self.buffer, endpos=self.position))
|
||||
if line > 1:
|
||||
column = self.position - self.buffer.rindex("\n", 0, self.position)
|
||||
else:
|
||||
column = self.position
|
||||
return line + 1, column + 1
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
"""Return the next token and advance the position."""
|
||||
if self._state == "start":
|
||||
match = self._stx_re.search(self.buffer, self.position)
|
||||
if not match:
|
||||
raise JESD3ParsingError("could not find STX marker")
|
||||
else:
|
||||
token = "start"
|
||||
self._state = "fields"
|
||||
self.checksum += sum(map(ord, match.group(0)))
|
||||
|
||||
elif self._state == "fields":
|
||||
match = self._ident_re.match(self.buffer, self.position)
|
||||
if match:
|
||||
token = match.group(0)
|
||||
match = self._field_res[token].match(self.buffer, self.position)
|
||||
if not match:
|
||||
raise JESD3ParsingError("field %s has invalid format at line %d, column %d"
|
||||
% (token, *self.line_column()))
|
||||
else:
|
||||
self.checksum += sum(map(ord, match.group(0)))
|
||||
|
||||
else:
|
||||
match = self._etx_re.match(self.buffer, self.position)
|
||||
if not match:
|
||||
raise JESD3ParsingError("unrecognized field at line %d, column %d (%r...)"
|
||||
% (*self.line_column(),
|
||||
self.buffer[self.position:self.position + 16]))
|
||||
else:
|
||||
token = "end"
|
||||
self._state = "end"
|
||||
self.checksum += 0x03
|
||||
|
||||
elif self._state == "end":
|
||||
raise StopIteration
|
||||
|
||||
self.position = match.end()
|
||||
return token, match.start(), match.groups()
|
||||
|
||||
|
||||
class JESD3Parser:
|
||||
def __init__(self, buffer, **kwargs):
|
||||
self._lexer = JESD3Lexer(buffer, **kwargs)
|
||||
self._position = 0
|
||||
|
||||
self.design_spec = ""
|
||||
self.notes = []
|
||||
self.fuse = None
|
||||
self._fuse_default = None
|
||||
self._fuse_bit_count = 0
|
||||
self.electrical_fuse = None
|
||||
self.user_fuse = None
|
||||
self.security_fuse = None
|
||||
self.device_id = None
|
||||
|
||||
def _parse_error(self, error):
|
||||
raise JESD3ParsingError("%s at line %d, column %d"
|
||||
% (error, *self._lexer.line_column(self._position)))
|
||||
|
||||
def parse(self):
|
||||
for token, position, args in self._lexer:
|
||||
self._position = position
|
||||
# print("lexem: %r %r" % (token, args))
|
||||
getattr(self, "_on_" + token)(*args)
|
||||
|
||||
def _on_start(self, design_spec):
|
||||
"""Start marker and design specification"""
|
||||
self.design_spec = design_spec
|
||||
|
||||
def _on_N(self, note):
|
||||
"""Note"""
|
||||
self.notes.append(note)
|
||||
|
||||
def _on_D(self):
|
||||
"""Device (obsolete)"""
|
||||
|
||||
def _on_QF(self, count):
|
||||
"""Fuse count"""
|
||||
if self.fuse is not None:
|
||||
self._parse_error("fuse count specified more than once")
|
||||
self.fuse = bitarray(int(count, 10), endian="little")
|
||||
|
||||
def _on_QP(self, count):
|
||||
"""Pin count (unsupported and ignored)"""
|
||||
|
||||
def _on_QV(self, count):
|
||||
"""Test vector count (unsupported)"""
|
||||
if int(count, 10) > 0:
|
||||
self._parse_error("test vectors are unsupported")
|
||||
|
||||
def _on_F(self, state):
|
||||
"""Fuse default state"""
|
||||
if self.fuse is None:
|
||||
self._parse_error("fuse default state specified before fuse count")
|
||||
if self._fuse_default is not None:
|
||||
self._parse_error("fuse default state specified more than once")
|
||||
if self._fuse_bit_count > 0:
|
||||
self._parse_error("fuse default state specified after fuse list")
|
||||
self._fuse_default = int(state, 2)
|
||||
self.fuse.setall(self._fuse_default)
|
||||
|
||||
def _on_L(self, index, values):
|
||||
"""Fuse list"""
|
||||
if self.fuse is None:
|
||||
self._parse_error("fuse list specified before fuse count")
|
||||
index = int(index, 10)
|
||||
values = bitarray(re.sub(r"[ \r\n]", "", values), endian="little")
|
||||
if index + len(values) > len(self.fuse):
|
||||
self._parse_error("fuse list specifies range [%d:%d] beyond last fuse %d"
|
||||
% (index, index + len(values), len(self.fuse)))
|
||||
self.fuse[index:index + len(values)] = values
|
||||
self._fuse_bit_count += len(values)
|
||||
|
||||
def _on_C(self, checksum):
|
||||
"""Fuse checksum"""
|
||||
expected_checksum = int(checksum, 16)
|
||||
actual_checksum = sum(self.fuse.tobytes()) & 0xffff
|
||||
if expected_checksum != actual_checksum:
|
||||
self._parse_error("fuse checksum mismatch: expected %04X, actual %04X"
|
||||
% (expected_checksum, actual_checksum))
|
||||
|
||||
def _set_electrical_fuse(self, value):
|
||||
if self.electrical_fuse is not None:
|
||||
self._parse_error("electrical fuse specified more than once")
|
||||
self.electrical_fuse = value
|
||||
|
||||
def _on_EH(self, value):
|
||||
"""Electrical fuse, hex"""
|
||||
self._set_electrical_fuse(int(value, 16))
|
||||
|
||||
def _on_E(self, value):
|
||||
"""Electrical fuse, binary"""
|
||||
self._set_electrical_fuse(int(value, 2))
|
||||
|
||||
def _set_user_fuse(self, value):
|
||||
if self.user_fuse is not None:
|
||||
self._parse_error("user fuse specified more than once")
|
||||
self.user_fuse = value
|
||||
|
||||
def _on_UA(self, value):
|
||||
"""User fuse, 7-bit ASCII"""
|
||||
int_value = 0
|
||||
for char in reversed(value):
|
||||
int_value <<= 7
|
||||
int_value |= ord(char)
|
||||
self._set_user_fuse(int_value)
|
||||
|
||||
def _on_UH(self, value):
|
||||
"""User fuse, hex"""
|
||||
self._set_user_fuse(int(value, 16))
|
||||
|
||||
def _on_U(self, value):
|
||||
"""User fuse, binary"""
|
||||
self._set_user_fuse(int(value, 2))
|
||||
|
||||
def _on_J(self, arch_code, pinout_code):
|
||||
"""Device identification"""
|
||||
if self.device_id is not None:
|
||||
self._parse_error("device identification specified more than once")
|
||||
self.device_id = (int(arch_code, 10), int(pinout_code, 10))
|
||||
|
||||
def _on_G(self, value):
|
||||
"""Security fuse"""
|
||||
if self.security_fuse is not None:
|
||||
self._parse_error("security fuse specified more than once")
|
||||
self.security_fuse = int(value, 2)
|
||||
|
||||
def _on_X(self, value):
|
||||
"""Default test condition (unsupported and ignored)"""
|
||||
|
||||
def _on_P(self, pin_numbers):
|
||||
"""Pin list (unsupported and ignored)"""
|
||||
|
||||
def _on_V(self, vector_number, test_conditions):
|
||||
"""Test vector (unsupported and ignored)"""
|
||||
|
||||
def _on_S(self, test_condition):
|
||||
"""Signature analysis starting vector (unsupported)"""
|
||||
self._parse_error("signature analysis is not supported")
|
||||
|
||||
def _on_R(self, test_sum):
|
||||
"""Signature analysis resulting vector (unsupported and ignored)"""
|
||||
|
||||
def _on_T(self, test_cycles):
|
||||
"""Signature analysis test cycle count (unsupported and ignored)"""
|
||||
|
||||
def _on_A(self, subfield, delay):
|
||||
"""Propagation delay for test vectors (unsupported and ignored)"""
|
||||
|
||||
def _on_end(self, checksum):
|
||||
"""End marker and checksum"""
|
||||
expected_checksum = int(checksum, 16)
|
||||
if expected_checksum == 0x0000:
|
||||
return
|
||||
actual_checksum = self._lexer.checksum & 0xffff
|
||||
if expected_checksum != actual_checksum:
|
||||
self._parse_error("transmission checksum mismatch: expected %04X, actual %04X"
|
||||
% (expected_checksum, actual_checksum))
|
||||
|
||||
if self._fuse_default is None and self._fuse_bit_count < len(self.fuse):
|
||||
self._parse_error("fuse default state is not specified, and only %d out of %d fuse "
|
||||
"bits are explicitly defined"
|
||||
% (self._fuse_bit_count, len(self.fuse)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
with open(sys.argv[1], "r") as f:
|
||||
parser = JESD3Parser(f.read(), quirk_no_design_spec=False)
|
||||
parser.parse()
|
||||
for i in range(0, len(parser.fuse) + 63, 64):
|
||||
print("%08x: %s" % (i, parser.fuse[i:i + 64].to01()))
|
|
@ -0,0 +1,22 @@
|
|||
JTAG conversion tools
|
||||
---------------------------------------
|
||||
|
||||
fuseconv.py : converts ATF150X .jed file into .svf file
|
||||
|
||||
The origin of the conversion tool is this git repo:
|
||||
https://github.com/whitequark/prjbureau
|
||||
|
||||
|
||||
svf2xsvf.py : converts .svf file into .xsvf file
|
||||
|
||||
The origin of the tool is this git repo:
|
||||
https://github.com/arduino/OpenOCD/tree/master/contrib/xsvf_tools
|
||||
|
||||
|
||||
Typically you produce a .jed file for your ATF150X device either by
|
||||
WinCUPL or by ATF15XX_Yosys (https://github.com/hoglet67/atf15xx_yosys/)
|
||||
and then run fuseconv.py and svf2xsvf.py to produce .xsvf file that can be
|
||||
used by Aftereburner's JTAG player.
|
||||
|
||||
See example_jed2xsvf.sh for more information how to run these tools.
|
||||
|
|
@ -0,0 +1,906 @@
|
|||
# Vendored from glasgow.protocol.jtag_svf
|
||||
|
||||
# Ref: https://www.asset-intertech.com/eresources/svf-serial-vector-format-specification-jtag-boundary-scan
|
||||
# Accession: G00022
|
||||
# Ref: http://www.jtagtest.com/pdf/svf_specification.pdf
|
||||
# Accession: G00023
|
||||
|
||||
import re
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from bitarray import bitarray
|
||||
|
||||
|
||||
__all__ = ["SVFParser", "SVFEventHandler"]
|
||||
|
||||
|
||||
def _hex_to_bitarray(input_nibbles):
|
||||
byte_len = (len(input_nibbles) + 1) // 2
|
||||
input_bytes = bytes.fromhex(input_nibbles.rjust(byte_len * 2, "0"))
|
||||
bits = bitarray(endian="little")
|
||||
bits.frombytes(input_bytes)
|
||||
bits.reverse()
|
||||
bits.bytereverse()
|
||||
return bits
|
||||
|
||||
|
||||
_commands = (
|
||||
"ENDDR", "ENDIR", "FREQUENCY", "HDR", "HIR", "PIO", "PIOMAP", "RUNTEST",
|
||||
"SDR", "SIR", "STATE", "TDR", "TIR", "TRST",
|
||||
)
|
||||
_parameters = (
|
||||
"ENDSTATE", "HZ", "MASK", "MAXIMUM", "SCK", "SEC", "SMASK", "TCK", "TDI", "TDO",
|
||||
)
|
||||
_trst_modes = (
|
||||
"ON", "OFF", "Z", "ABSENT"
|
||||
)
|
||||
_tap_states = (
|
||||
"RESET", "IDLE", "DRSELECT", "DRCAPTURE", "DRSHIFT", "DREXIT1", "DRPAUSE",
|
||||
"DREXIT2", "DRUPDATE", "IRSELECT", "IRCAPTURE", "IRSHIFT", "IREXIT1", "IRPAUSE",
|
||||
"IREXIT2", "IRUPDATE",
|
||||
)
|
||||
_tap_stable_states = (
|
||||
"RESET", "IDLE", "IRPAUSE", "DRPAUSE"
|
||||
)
|
||||
|
||||
|
||||
class SVFParsingError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class SVFLexer:
|
||||
"""
|
||||
A Serial Vector Format lexer.
|
||||
|
||||
Comments (``! comment``, ``// comment``) are ignored.
|
||||
|
||||
The following tokens are recognized:
|
||||
* Keyword (``HIR``, ``SIR``, ``TIO``, ..., ``;``), returned as Python ``str``;
|
||||
* Integer (``8``, ``16``, ...), returned as Python ``int``;
|
||||
* Real (``1E0``, ``1E+0``, ``1E-0``, ...), returned as Python ``float``;
|
||||
* Bit array (``(0)``, ``(1234)``, ``(F00F)``, ...), returned as Python ``bitarray``;
|
||||
* Literal (``(HLUDXZHHLL)``, ``(IN FOO)``, ...), returned as Python ``tuple(str,)``;
|
||||
* End of file, returned as Python ``None``.
|
||||
|
||||
:type buffer: str
|
||||
:attr buffer:
|
||||
Input buffer.
|
||||
|
||||
:type position: int
|
||||
:attr position:
|
||||
Offset into buffer from which the next token will be read.
|
||||
"""
|
||||
|
||||
_keywords = _commands + _parameters + _trst_modes + _tap_states + (";",)
|
||||
_scanner = tuple((re.compile(src, re.A|re.I|re.M), act) for src, act in (
|
||||
(r"\s+",
|
||||
None),
|
||||
(r"(?:!|//)([^\n]*)(?:\n|\Z)",
|
||||
None),
|
||||
(r"({})(?=\s+|[;()]|\Z)".format("|".join(_keywords)),
|
||||
lambda m: m[1]),
|
||||
(r"(\d+)(?=[^0-9\.E])",
|
||||
lambda m: int(m[1])),
|
||||
(r"(\d+(?:\.\d+)?(?:E[+-]?\d+)?)",
|
||||
lambda m: float(m[1])),
|
||||
(r"\(\s*([0-9A-F\s]+)\s*\)",
|
||||
lambda m: _hex_to_bitarray(re.sub(r"\s+", "", m[1]))),
|
||||
(r"\(\s*(.+?)\s*\)",
|
||||
lambda m: (m[1],)),
|
||||
(r"\Z",
|
||||
lambda m: None),
|
||||
))
|
||||
|
||||
def __init__(self, buffer):
|
||||
self.buffer = buffer
|
||||
self.position = 0
|
||||
|
||||
def line_column(self, position=None):
|
||||
"""
|
||||
Return a ``(line, column)`` tuple for the given or, if not specified, current position.
|
||||
|
||||
Both the line and the column start at 1.
|
||||
"""
|
||||
line = len(re.compile(r"\n").findall(self.buffer, endpos=self.position))
|
||||
if line > 1:
|
||||
column = self.position - self.buffer.rindex("\n", 0, self.position)
|
||||
else:
|
||||
column = self.position
|
||||
return line + 1, column + 1
|
||||
|
||||
def _lex(self):
|
||||
while True:
|
||||
for token_re, action in self._scanner:
|
||||
match = token_re.match(self.buffer, self.position)
|
||||
# print(token_re, match)
|
||||
if match:
|
||||
if action is None:
|
||||
self.position = match.end()
|
||||
break
|
||||
else:
|
||||
return action(match), match.end()
|
||||
else:
|
||||
raise SVFParsingError("unrecognized SVF data at line %d, column %d (%s...)"
|
||||
% (*self.line_column(),
|
||||
self.buffer[self.position:self.position + 16]))
|
||||
|
||||
def peek(self):
|
||||
"""Return the next token without advancing the position."""
|
||||
token, _ = self._lex()
|
||||
return token
|
||||
|
||||
def next(self):
|
||||
"""Return the next token and advance the position."""
|
||||
token, next_pos = self._lex()
|
||||
self.position = next_pos
|
||||
return token
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
token = self.next()
|
||||
if token is None:
|
||||
raise StopIteration
|
||||
return token
|
||||
|
||||
|
||||
class SVFParser:
|
||||
"""
|
||||
A Serial Vector Format streaming parser.
|
||||
|
||||
This parser maintains and allows querying lexical state (e.g. "sticky" ``TDI`` is
|
||||
automatically tracked), and invokes the SVF event handler for all commands so that
|
||||
any necessary action may be taken.
|
||||
"""
|
||||
def __init__(self, buffer, handler):
|
||||
self._lexer = SVFLexer(buffer)
|
||||
self._handler = handler
|
||||
self._position = 0
|
||||
self._token = None
|
||||
self._cmd_pos = 0
|
||||
|
||||
self._param_tdi = \
|
||||
{"HIR": None, "HDR": None, "SIR": None, "SDR": None, "TIR": None, "TDR": None}
|
||||
self._param_mask = \
|
||||
{"HIR": None, "HDR": None, "SIR": None, "SDR": None, "TIR": None, "TDR": None}
|
||||
self._param_smask = \
|
||||
{"HIR": None, "HDR": None, "SIR": None, "SDR": None, "TIR": None, "TDR": None}
|
||||
|
||||
self._param_run_state = "IDLE"
|
||||
self._param_end_state = "IDLE"
|
||||
|
||||
def _try(self, action, *args):
|
||||
try:
|
||||
old_position = self._lexer.position
|
||||
return action(*args)
|
||||
except SVFParsingError as e:
|
||||
self._lexer.position = old_position
|
||||
return None
|
||||
|
||||
def _parse_token(self):
|
||||
self._position = self._lexer.position
|
||||
self._token = self._lexer.next()
|
||||
# print("token %s @ %d" % (self._token, self._position))
|
||||
return self._token
|
||||
|
||||
def _parse_error(self, error):
|
||||
raise SVFParsingError("%s at line %d, column %d"
|
||||
% (error, *self._lexer.line_column(self._position)))
|
||||
|
||||
def _parse_unexpected(self, expected, valid=()):
|
||||
if isinstance(self._token, str):
|
||||
actual = self._token
|
||||
elif isinstance(self._token, int):
|
||||
actual = "integer"
|
||||
elif isinstance(self._token, float):
|
||||
actual = "real"
|
||||
elif isinstance(self._token, bitarray):
|
||||
actual = "scan data"
|
||||
elif isinstance(self._token, tuple):
|
||||
actual = "(%s)" % (*self._token,)
|
||||
elif self._token is None:
|
||||
actual = "end of file"
|
||||
else:
|
||||
assert False
|
||||
if valid:
|
||||
self._parse_error("expected %s (one of %s), found %s"
|
||||
% (expected, ", ".join(valid), actual))
|
||||
else:
|
||||
self._parse_error("expected %s, found %s"
|
||||
% (expected, actual))
|
||||
|
||||
def _parse_keyword(self, keyword):
|
||||
if self._parse_token() == keyword:
|
||||
return self._token
|
||||
else:
|
||||
self._parse_unexpected("semicolon" if keyword == ";" else keyword)
|
||||
|
||||
def _parse_keywords(self, keywords):
|
||||
if self._parse_token() in keywords:
|
||||
return self._token
|
||||
else:
|
||||
self._parse_unexpected("one of {}".format(", ".join(keywords)))
|
||||
|
||||
def _parse_value(self, kind):
|
||||
if isinstance(self._parse_token(), kind):
|
||||
return self._token
|
||||
else:
|
||||
if kind == int:
|
||||
expected = "integer"
|
||||
elif kind == float:
|
||||
expected = "real"
|
||||
elif kind == (int, float):
|
||||
expected = "number"
|
||||
elif kind == bitarray:
|
||||
expected = "scan data"
|
||||
elif kind == tuple:
|
||||
expected = "data"
|
||||
else:
|
||||
assert False
|
||||
self._parse_unexpected(expected)
|
||||
|
||||
def _parse_trst_mode(self):
|
||||
if self._parse_token() in _trst_modes:
|
||||
return self._token
|
||||
else:
|
||||
self._parse_unexpected("TRST mode", _trst_modes)
|
||||
|
||||
def _parse_tap_state(self):
|
||||
if self._parse_token() in _tap_states:
|
||||
return self._token
|
||||
else:
|
||||
self._parse_unexpected("TAP state", _tap_states)
|
||||
|
||||
def _parse_tap_stable_state(self):
|
||||
if self._parse_token() in _tap_stable_states:
|
||||
return self._token
|
||||
else:
|
||||
self._parse_unexpected("stable TAP state", _tap_stable_states)
|
||||
|
||||
def _parse_scan_data(self, length):
|
||||
value = self._parse_value(bitarray)
|
||||
if value[length:].count(1) != 0:
|
||||
residue = value[length:]
|
||||
residue.reverse()
|
||||
self._parse_error("scan data length %d exceeds command length %d"
|
||||
% (len(value), length))
|
||||
|
||||
if length > len(value):
|
||||
padding = bitarray(length - len(value), endian="little")
|
||||
padding.setall(0)
|
||||
value.extend(padding)
|
||||
return value
|
||||
else:
|
||||
return value[:length]
|
||||
|
||||
def parse_command(self):
|
||||
self._cmd_pos = self._lexer.position
|
||||
|
||||
command = self._parse_token()
|
||||
if command is None:
|
||||
return False
|
||||
|
||||
elif command == "FREQUENCY":
|
||||
cycles = self._try(self._parse_value, (int, float))
|
||||
if cycles is not None:
|
||||
self._parse_keyword("HZ")
|
||||
self._parse_keyword(";")
|
||||
|
||||
result = self._handler.svf_frequency(frequency=cycles)
|
||||
|
||||
elif command == "TRST":
|
||||
mode = self._parse_trst_mode()
|
||||
self._parse_keyword(";")
|
||||
|
||||
result = self._handler.svf_trst(mode=mode)
|
||||
|
||||
elif command == "STATE":
|
||||
states = []
|
||||
while True:
|
||||
state = self._try(self._parse_tap_state)
|
||||
if state is None: break
|
||||
states.append(state)
|
||||
|
||||
self._parse_keyword(";")
|
||||
|
||||
if not states:
|
||||
self._parse_error("at least one state required")
|
||||
if states[-1] not in _tap_stable_states:
|
||||
self._parse_error("last state must be a stable state")
|
||||
|
||||
*path_states, stable_state = states
|
||||
result = self._handler.svf_state(state=stable_state, path=path_states)
|
||||
|
||||
elif command in ("ENDIR", "ENDDR"):
|
||||
stable_state = self._parse_tap_stable_state()
|
||||
self._parse_keyword(";")
|
||||
|
||||
if command == "ENDIR":
|
||||
result = self._handler.svf_endir(state=stable_state)
|
||||
if command == "ENDDR":
|
||||
result = self._handler.svf_enddr(state=stable_state)
|
||||
|
||||
elif command in ("HIR", "SIR", "TIR", "HDR", "SDR", "TDR"):
|
||||
length = self._parse_value(int)
|
||||
|
||||
if self._param_mask[command] is None or len(self._param_mask[command]) != length:
|
||||
self._param_mask[command] = bitarray(length, endian="little")
|
||||
self._param_mask[command].setall(1)
|
||||
if self._param_smask[command] is None or len(self._param_smask[command]) != length:
|
||||
self._param_smask[command] = bitarray(length, endian="little")
|
||||
self._param_smask[command].setall(1)
|
||||
|
||||
param_tdi = self._param_tdi[command]
|
||||
param_tdo = None
|
||||
param_mask = self._param_mask[command]
|
||||
param_smask = self._param_smask[command]
|
||||
parameters = set()
|
||||
while True:
|
||||
parameter = self._try(self._parse_keywords, ("TDI", "TDO", "MASK", "SMASK"))
|
||||
if parameter is None: break
|
||||
|
||||
value = self._parse_scan_data(length)
|
||||
if parameter in parameters:
|
||||
self._parse_error("parameter %s specified twice" % parameter)
|
||||
parameters.add(parameter)
|
||||
|
||||
if parameter == "TDI":
|
||||
self._param_tdi[command] = value
|
||||
param_tdi = value
|
||||
if parameter == "TDO":
|
||||
param_tdo = value
|
||||
if parameter == "MASK":
|
||||
self._param_mask[command] = value
|
||||
param_mask = value
|
||||
if parameter == "SMASK":
|
||||
self._param_smask[command] = value
|
||||
param_smask = value
|
||||
|
||||
self._parse_keyword(";")
|
||||
|
||||
if param_tdi is None and length == 0:
|
||||
param_tdi = bitarray("", endian="little")
|
||||
elif param_tdi is None:
|
||||
self._parse_error("initial value for parameter TDI required")
|
||||
if len(param_tdi) != length:
|
||||
self._parse_error("parameter TDI needs to be specified again because "
|
||||
"the length changed")
|
||||
|
||||
if param_tdo is None:
|
||||
# Make it a bit easier for downstream; set MASK (but not remembered MASK)
|
||||
# to "all don't care" if there's no TDO specified.
|
||||
param_mask = bitarray(param_mask)
|
||||
param_mask.setall(0)
|
||||
|
||||
if command == "HIR":
|
||||
result = self._handler.svf_hir(tdi=param_tdi, smask=param_smask,
|
||||
tdo=param_tdo, mask=param_mask)
|
||||
if command == "SIR":
|
||||
result = self._handler.svf_sir(tdi=param_tdi, smask=param_smask,
|
||||
tdo=param_tdo, mask=param_mask)
|
||||
if command == "TIR":
|
||||
result = self._handler.svf_tir(tdi=param_tdi, smask=param_smask,
|
||||
tdo=param_tdo, mask=param_mask)
|
||||
if command == "HDR":
|
||||
result = self._handler.svf_hdr(tdi=param_tdi, smask=param_smask,
|
||||
tdo=param_tdo, mask=param_mask)
|
||||
if command == "SDR":
|
||||
result = self._handler.svf_sdr(tdi=param_tdi, smask=param_smask,
|
||||
tdo=param_tdo, mask=param_mask)
|
||||
if command == "TDR":
|
||||
result = self._handler.svf_tdr(tdi=param_tdi, smask=param_smask,
|
||||
tdo=param_tdo, mask=param_mask)
|
||||
|
||||
elif command == "RUNTEST":
|
||||
run_state = self._try(self._parse_tap_stable_state)
|
||||
run_params = self._try(lambda:
|
||||
(self._parse_value(int), self._parse_keywords(("TCK", "SCK"))))
|
||||
if run_params is None:
|
||||
run_count, run_clock = None, "TCK"
|
||||
min_time, _ = \
|
||||
self._parse_value((int, float)), self._parse_keyword("SEC")
|
||||
else:
|
||||
run_count, run_clock = run_params
|
||||
min_time, _ = self._try(lambda:
|
||||
(self._parse_value((int, float)), self._parse_keyword("SEC"))) \
|
||||
or (None, None)
|
||||
if self._try(self._parse_keyword, "MAXIMUM"):
|
||||
max_time, _ = \
|
||||
self._parse_value((int, float)), self._parse_keyword("SEC")
|
||||
else:
|
||||
max_time = None
|
||||
if self._try(self._parse_keyword, "ENDSTATE"):
|
||||
end_state = self._parse_tap_stable_state()
|
||||
else:
|
||||
end_state = None
|
||||
self._parse_keyword(";")
|
||||
|
||||
if run_state is None:
|
||||
run_state = self._param_run_state
|
||||
else:
|
||||
self._param_run_state = run_state
|
||||
if end_state is None:
|
||||
end_state = run_state
|
||||
|
||||
if end_state is None:
|
||||
end_state = self._param_end_state
|
||||
else:
|
||||
self._param_end_state = end_state
|
||||
|
||||
if run_clock is None:
|
||||
run_clock = "TCK"
|
||||
|
||||
if max_time is not None and min_time is not None and max_time < min_time:
|
||||
self._parse_error("maximum time must be greater than minimum time")
|
||||
|
||||
result = self._handler.svf_runtest(run_state=run_state,
|
||||
run_count=run_count, run_clock=run_clock,
|
||||
min_time =min_time, max_time=max_time,
|
||||
end_state=end_state)
|
||||
|
||||
elif command == "PIOMAP":
|
||||
mapping, = self._parse_value(tuple)
|
||||
self._parse_keyword(";")
|
||||
|
||||
result = self._handler.svf_piomap(mapping=mapping)
|
||||
|
||||
elif command == "PIO":
|
||||
vector, = self._parse_value(tuple)
|
||||
self._parse_keyword(";")
|
||||
|
||||
result = self._handler.svf_pio(vector=vector)
|
||||
|
||||
else:
|
||||
self._parse_unexpected("command", _commands)
|
||||
|
||||
return result or True
|
||||
|
||||
def last_command(self):
|
||||
return self._lexer.buffer[self._cmd_pos:self._lexer.position]
|
||||
|
||||
def parse_file(self):
|
||||
while self.parse_command(): pass
|
||||
|
||||
|
||||
class SVFEventHandler(metaclass=ABCMeta):
|
||||
"""
|
||||
An abstract base class for Serial Vector Format parsing events.
|
||||
|
||||
The methods of this class are called when a well-formed SVF command is encountered.
|
||||
The parser takes care of maintaining all lexical state (e.g. "sticky" parameters),
|
||||
but all logical state is maintained by the event handler.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def svf_frequency(self, frequency):
|
||||
"""Called when the ``FREQUENCY`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_trst(self, mode):
|
||||
"""Called when the ``TRST`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_state(self, state, path):
|
||||
"""Called when the ``STATE`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_endir(self, state):
|
||||
"""Called when the ``ENDIR`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_enddr(self, state):
|
||||
"""Called when the ``ENDDR`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_hir(self, tdi, smask, tdo, mask):
|
||||
"""Called when the ``HIR`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_sir(self, tdi, smask, tdo, mask):
|
||||
"""Called when the ``SIR`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_tir(self, tdi, smask, tdo, mask):
|
||||
"""Called when the ``TIR`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_hdr(self, tdi, smask, tdo, mask):
|
||||
"""Called when the ``HDR`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_sdr(self, tdi, smask, tdo, mask):
|
||||
"""Called when the ``SDR`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_tdr(self, tdi, smask, tdo, mask):
|
||||
"""Called when the ``TDR`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_runtest(self, run_state, run_count, run_clock, min_time, max_time, end_state):
|
||||
"""Called when the ``RUNTEST`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_piomap(self, mapping):
|
||||
"""Called when the ``PIOMAP`` command is encountered."""
|
||||
|
||||
@abstractmethod
|
||||
def svf_pio(self, vector):
|
||||
"""Called when the ``PIO`` command is encountered."""
|
||||
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class SVFLexerTestCase(unittest.TestCase):
|
||||
def assertLexes(self, source, tokens):
|
||||
self.lexer = SVFLexer(source)
|
||||
self.assertEqual(list(self.lexer), tokens)
|
||||
|
||||
def test_eof(self):
|
||||
self.assertLexes("", [])
|
||||
|
||||
def test_comment(self):
|
||||
self.assertLexes("!foo",
|
||||
[])
|
||||
self.assertLexes("//foo",
|
||||
[])
|
||||
self.assertLexes("//foo\n!bar\n",
|
||||
[])
|
||||
self.assertLexes("//foo\n!bar\nTRST",
|
||||
["TRST"])
|
||||
|
||||
def test_keyword(self):
|
||||
self.assertLexes("TRST",
|
||||
["TRST"])
|
||||
self.assertLexes("TRST OFF;",
|
||||
["TRST", "OFF", ";"])
|
||||
|
||||
def test_integer(self):
|
||||
self.assertLexes("8", [8])
|
||||
self.assertLexes("12", [12])
|
||||
|
||||
def test_real(self):
|
||||
self.assertLexes("1E6", [1e6])
|
||||
self.assertLexes("1E+6", [1e6])
|
||||
self.assertLexes("1E-6", [1e-6])
|
||||
self.assertLexes("1.1E6", [1.1e6])
|
||||
self.assertLexes("1.1", [1.1])
|
||||
|
||||
def test_bitarray(self):
|
||||
self.assertLexes("(0)", [bitarray("00000000")])
|
||||
self.assertLexes("(1)", [bitarray("10000000")])
|
||||
self.assertLexes("(F)", [bitarray("11110000")])
|
||||
self.assertLexes("(f)", [bitarray("11110000")])
|
||||
self.assertLexes("(0F)", [bitarray("11110000")])
|
||||
self.assertLexes("(A\n5)", [bitarray("10100101")]) # Test literals split over two lines
|
||||
self.assertLexes("(A\n\t5)", [bitarray("10100101")]) # With potential whitespace
|
||||
self.assertLexes("(A\n 5)", [bitarray("10100101")])
|
||||
self.assertLexes("(A\r\n5)", [bitarray("10100101")]) # Support both LF & LFCR
|
||||
self.assertLexes("(A\r\n\t5)", [bitarray("10100101")])
|
||||
self.assertLexes("(A\r\n 5)", [bitarray("10100101")])
|
||||
self.assertLexes("(FF)", [bitarray("11111111")])
|
||||
self.assertLexes("(1AA)", [bitarray("0101010110000000")])
|
||||
|
||||
def test_literal(self):
|
||||
self.assertLexes("(HHZZL)", [("HHZZL",)])
|
||||
self.assertLexes("(IN FOO)", [("IN FOO",)])
|
||||
|
||||
def test_error(self):
|
||||
with self.assertRaises(SVFParsingError):
|
||||
SVFLexer("XXX").next()
|
||||
|
||||
|
||||
class SVFMockEventHandler:
|
||||
def __init__(self):
|
||||
self.events = []
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith("svf_"):
|
||||
def svf_event(**kwargs):
|
||||
self.events.append((name, kwargs))
|
||||
return svf_event
|
||||
else:
|
||||
return super().__getattr__(name)
|
||||
|
||||
|
||||
class SVFParserTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.maxDiff = None
|
||||
|
||||
def assertParses(self, source, events):
|
||||
self.handler = SVFMockEventHandler()
|
||||
self.parser = SVFParser(source, self.handler)
|
||||
self.parser.parse_file()
|
||||
self.assertEqual(self.handler.events, events)
|
||||
|
||||
def assertErrors(self, source, error):
|
||||
with self.assertRaisesRegex(SVFParsingError, r"^{}".format(re.escape(error))):
|
||||
self.handler = SVFMockEventHandler()
|
||||
self.parser = SVFParser(source, self.handler)
|
||||
self.parser.parse_file()
|
||||
|
||||
def test_frequency(self):
|
||||
self.assertParses("FREQUENCY;",
|
||||
[("svf_frequency", {"frequency": None})])
|
||||
self.assertParses("FREQUENCY 1E6 HZ;",
|
||||
[("svf_frequency", {"frequency": 1e6})])
|
||||
self.assertParses("FREQUENCY 1000 HZ;",
|
||||
[("svf_frequency", {"frequency": 1000})])
|
||||
|
||||
self.assertErrors("FREQUENCY 1E6;",
|
||||
"expected HZ")
|
||||
|
||||
def test_trst(self):
|
||||
self.assertParses("TRST ON;",
|
||||
[("svf_trst", {"mode": "ON"})])
|
||||
self.assertParses("TRST OFF;",
|
||||
[("svf_trst", {"mode": "OFF"})])
|
||||
self.assertParses("TRST Z;",
|
||||
[("svf_trst", {"mode": "Z"})])
|
||||
self.assertParses("TRST ABSENT;",
|
||||
[("svf_trst", {"mode": "ABSENT"})])
|
||||
|
||||
self.assertErrors("TRST HZ;",
|
||||
"expected TRST mode")
|
||||
|
||||
def test_state(self):
|
||||
self.assertParses("STATE IDLE;",
|
||||
[("svf_state", {"state": "IDLE", "path": []})])
|
||||
self.assertParses("STATE IRUPDATE IDLE;",
|
||||
[("svf_state", {"state": "IDLE", "path": ["IRUPDATE"]})])
|
||||
self.assertParses("STATE IREXIT2 IRUPDATE IDLE;",
|
||||
[("svf_state", {"state": "IDLE", "path": ["IREXIT2", "IRUPDATE"]})])
|
||||
|
||||
self.assertErrors("STATE;",
|
||||
"at least one state required")
|
||||
self.assertErrors("STATE IRSHIFT;",
|
||||
"last state must be a stable state")
|
||||
self.assertErrors("STATE RESET IRSHIFT;",
|
||||
"last state must be a stable state")
|
||||
|
||||
def test_endir_enddr(self):
|
||||
for command, event in [
|
||||
("ENDIR", "svf_endir"),
|
||||
("ENDDR", "svf_enddr")
|
||||
]:
|
||||
self.assertParses("{c} IRPAUSE;".format(c=command),
|
||||
[(event, {"state": "IRPAUSE"})])
|
||||
|
||||
self.assertErrors("{c} IRSHIFT;".format(c=command),
|
||||
"expected stable TAP state")
|
||||
self.assertErrors("{c};".format(c=command),
|
||||
"expected stable TAP state")
|
||||
|
||||
def test_hir_sir_tir_hdr_sdr_tdr(self):
|
||||
for command, event in [
|
||||
("HIR", "svf_hir"),
|
||||
("SIR", "svf_sir"),
|
||||
("TIR", "svf_tir"),
|
||||
("HDR", "svf_hdr"),
|
||||
("SDR", "svf_sdr"),
|
||||
("TDR", "svf_tdr"),
|
||||
]:
|
||||
self.assertParses("{c} 0;".format(c=command), [
|
||||
(event, {
|
||||
"tdi": bitarray(""),
|
||||
"smask": bitarray(""),
|
||||
"tdo": None,
|
||||
"mask": bitarray(""),
|
||||
}),
|
||||
])
|
||||
self.assertParses("{c} 8 TDI(a);".format(c=command), [
|
||||
(event, {
|
||||
"tdi": bitarray("01010000"),
|
||||
"smask": bitarray("11111111"),
|
||||
"tdo": None,
|
||||
"mask": bitarray("00000000"),
|
||||
}),
|
||||
])
|
||||
self.assertParses("{c} 6 TDI(0a);".format(c=command), [
|
||||
(event, {
|
||||
"tdi": bitarray("010100"),
|
||||
"smask": bitarray("111111"),
|
||||
"tdo": None,
|
||||
"mask": bitarray("000000"),
|
||||
}),
|
||||
])
|
||||
self.assertParses("{c} 8 TDI(a); {c} 8;".format(c=command), [
|
||||
(event, {
|
||||
"tdi": bitarray("01010000"),
|
||||
"smask": bitarray("11111111"),
|
||||
"tdo": None,
|
||||
"mask": bitarray("00000000"),
|
||||
}),
|
||||
(event, {
|
||||
"tdi": bitarray("01010000"),
|
||||
"smask": bitarray("11111111"),
|
||||
"tdo": None,
|
||||
"mask": bitarray("00000000"),
|
||||
}),
|
||||
])
|
||||
self.assertParses("{c} 8 TDI(a) SMASK(3); {c} 8; {c} 12 TDI(b);"
|
||||
.format(c=command), [
|
||||
(event, {
|
||||
"tdi": bitarray("01010000"),
|
||||
"smask": bitarray("11000000"),
|
||||
"tdo": None,
|
||||
"mask": bitarray("00000000"),
|
||||
}),
|
||||
(event, {
|
||||
"tdi": bitarray("01010000"),
|
||||
"smask": bitarray("11000000"),
|
||||
"tdo": None,
|
||||
"mask": bitarray("00000000"),
|
||||
}),
|
||||
(event, {
|
||||
"tdi": bitarray("110100000000"),
|
||||
"smask": bitarray("111111111111"),
|
||||
"tdo": None,
|
||||
"mask": bitarray("000000000000"),
|
||||
}),
|
||||
])
|
||||
self.assertParses("{c} 8 TDI(0) TDO(a) MASK(3); {c} 8; "
|
||||
"{c} 8 TDO(1); {c} 12 TDI(0) TDO(b);"
|
||||
.format(c=command), [
|
||||
(event, {
|
||||
"tdi": bitarray("00000000"),
|
||||
"smask": bitarray("11111111"),
|
||||
"tdo": bitarray("01010000"),
|
||||
"mask": bitarray("11000000"),
|
||||
}),
|
||||
(event, {
|
||||
"tdi": bitarray("00000000"),
|
||||
"smask": bitarray("11111111"),
|
||||
"tdo": None,
|
||||
"mask": bitarray("00000000"),
|
||||
}),
|
||||
(event, {
|
||||
"tdi": bitarray("00000000"),
|
||||
"smask": bitarray("11111111"),
|
||||
"tdo": bitarray("10000000"),
|
||||
"mask": bitarray("11000000"),
|
||||
}),
|
||||
(event, {
|
||||
"tdi": bitarray("000000000000"),
|
||||
"smask": bitarray("111111111111"),
|
||||
"tdo": bitarray("110100000000"),
|
||||
"mask": bitarray("111111111111"),
|
||||
}),
|
||||
])
|
||||
|
||||
self.assertErrors("{c} 8 TDI(aaa);".format(c=command),
|
||||
"scan data length 12 exceeds command length 8")
|
||||
self.assertErrors("{c} 8 TDI(0) TDI(0);".format(c=command),
|
||||
"parameter TDI specified twice")
|
||||
self.assertErrors("{c} 8;".format(c=command),
|
||||
"initial value for parameter TDI required")
|
||||
self.assertErrors("{c} 8 TDI(aa); {c} 12;".format(c=command),
|
||||
"parameter TDI needs to be specified again because "
|
||||
"the length changed")
|
||||
|
||||
def test_runtest(self):
|
||||
self.assertParses("RUNTEST 20000 TCK;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 20000, "run_clock": "TCK",
|
||||
"min_time": None, "max_time": None, "end_state": "IDLE"
|
||||
}),
|
||||
])
|
||||
self.assertParses("RUNTEST 20000 TCK 1E3 SEC;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 20000, "run_clock": "TCK",
|
||||
"min_time": 1e3, "max_time": None, "end_state": "IDLE"
|
||||
}),
|
||||
])
|
||||
self.assertParses("RUNTEST 20000 TCK 1E3 SEC MAXIMUM 1E6 SEC;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 20000, "run_clock": "TCK",
|
||||
"min_time": 1e3, "max_time": 1e6, "end_state": "IDLE"
|
||||
}),
|
||||
])
|
||||
self.assertParses("RUNTEST 20000 TCK 1E3 SEC MAXIMUM 1E6 SEC ENDSTATE RESET;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 20000, "run_clock": "TCK",
|
||||
"min_time": 1e3, "max_time": 1e6, "end_state": "RESET"
|
||||
}),
|
||||
])
|
||||
self.assertParses("RUNTEST 20000 TCK 1E3 SEC MAXIMUM 1E6 SEC ENDSTATE RESET;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 20000, "run_clock": "TCK",
|
||||
"min_time": 1e3, "max_time": 1e6, "end_state": "RESET"
|
||||
}),
|
||||
])
|
||||
self.assertParses("RUNTEST 20000 TCK ENDSTATE RESET; RUNTEST 100 TCK;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 20000, "run_clock": "TCK",
|
||||
"min_time": None, "max_time": None, "end_state": "RESET"
|
||||
}),
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 100, "run_clock": "TCK",
|
||||
"min_time": None, "max_time": None, "end_state": "RESET"
|
||||
}),
|
||||
])
|
||||
self.assertParses("RUNTEST RESET 20000 TCK ENDSTATE RESET; RUNTEST IDLE 100 TCK;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "RESET", "run_count": 20000, "run_clock": "TCK",
|
||||
"min_time": None, "max_time": None, "end_state": "RESET"
|
||||
}),
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 100, "run_clock": "TCK",
|
||||
"min_time": None, "max_time": None, "end_state": "IDLE"
|
||||
}),
|
||||
])
|
||||
|
||||
self.assertParses("RUNTEST 20000 SCK;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 20000, "run_clock": "SCK",
|
||||
"min_time": None, "max_time": None, "end_state": "IDLE"
|
||||
}),
|
||||
])
|
||||
|
||||
self.assertParses("RUNTEST 1 SEC;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": None, "run_clock": "TCK",
|
||||
"min_time": 1, "max_time": None, "end_state": "IDLE"
|
||||
}),
|
||||
])
|
||||
self.assertParses("RUNTEST 1 SEC MAXIMUM 2 SEC;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": None, "run_clock": "TCK",
|
||||
"min_time": 1, "max_time": 2, "end_state": "IDLE"
|
||||
}),
|
||||
])
|
||||
self.assertParses("RUNTEST 200 TCK ENDSTATE RESET; RUNTEST 1 SEC;", [
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": 200, "run_clock": "TCK",
|
||||
"min_time": None, "max_time": None, "end_state": "RESET"
|
||||
}),
|
||||
("svf_runtest", {
|
||||
"run_state": "IDLE", "run_count": None, "run_clock": "TCK",
|
||||
"min_time": 1, "max_time": None, "end_state": "RESET"
|
||||
}),
|
||||
])
|
||||
|
||||
self.assertErrors("RUNTEST;",
|
||||
"expected number")
|
||||
self.assertErrors("RUNTEST 2 SEC MAXIMUM 1 SEC;",
|
||||
"maximum time must be greater than minimum time")
|
||||
|
||||
def test_piomap(self):
|
||||
self.assertParses("PIOMAP (IN FOO OUT BAR);",
|
||||
[("svf_piomap", {"mapping": "IN FOO OUT BAR"})])
|
||||
|
||||
self.assertErrors("PIOMAP;",
|
||||
"expected data")
|
||||
|
||||
def test_pio(self):
|
||||
self.assertParses("PIO (LHZX);",
|
||||
[("svf_pio", {"vector": "LHZX"})])
|
||||
|
||||
self.assertErrors("PIO;",
|
||||
"expected data")
|
||||
|
||||
def test_last_command(self):
|
||||
handler = SVFMockEventHandler()
|
||||
parser = SVFParser(" TRST OFF; SIR 8 TDI (aa); ", handler)
|
||||
parser.parse_command()
|
||||
self.assertEqual(parser.last_command(), " TRST OFF;")
|
||||
parser.parse_command()
|
||||
self.assertEqual(parser.last_command(), " SIR 8 TDI (aa);")
|
||||
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
|
||||
class SVFPrintingEventHandler:
|
||||
def __getattr__(self, name):
|
||||
if name.startswith("svf_"):
|
||||
def svf_event(**kwargs):
|
||||
print((name, kwargs))
|
||||
return svf_event
|
||||
else:
|
||||
return super().__getattr__(name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
with open(sys.argv[1]) as f:
|
||||
SVFParser(f.read(), SVFPrintingEventHandler()).parse_file()
|
|
@ -0,0 +1,729 @@
|
|||
#!/usr/bin/python3.0
|
||||
|
||||
# Copyright 2008, SoftPLC Corporation http://softplc.com
|
||||
# Dick Hollenbeck dick@softplc.com
|
||||
|
||||
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, you may find one here:
|
||||
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# or you may search the http://www.gnu.org website for the version 2 license,
|
||||
# or you may write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
|
||||
# A python program to convert an SVF file to an XSVF file. There is an
|
||||
# option to include comments containing the source file line number from the origin
|
||||
# SVF file before each outputted XSVF statement.
|
||||
#
|
||||
# We deviate from the XSVF spec in that we introduce a new command called
|
||||
# XWAITSTATE which directly flows from the SVF RUNTEST command. Unfortunately
|
||||
# XRUNSTATE was ill conceived and is not used here. We also add support for the
|
||||
# three Lattice extensions to SVF: LCOUNT, LDELAY, and LSDR. The xsvf file
|
||||
# generated from this program is suitable for use with the xsvf player in
|
||||
# OpenOCD with my modifications to xsvf.c.
|
||||
#
|
||||
# This program is written for python 3.0, and it is not easy to change this
|
||||
# back to 2.x. You may find it easier to use python 3.x even if that means
|
||||
# building it.
|
||||
|
||||
|
||||
import re
|
||||
import sys
|
||||
import struct
|
||||
|
||||
|
||||
# There are both ---<Lexer>--- and ---<Parser>--- sections to this program
|
||||
|
||||
|
||||
if len( sys.argv ) < 3:
|
||||
print("usage %s <svf_filename> <xsvf_filename>" % sys.argv[0])
|
||||
exit(1)
|
||||
|
||||
|
||||
inputFilename = sys.argv[1]
|
||||
outputFilename = sys.argv[2]
|
||||
|
||||
#doCOMMENTs = True # Save XCOMMENTs in the output xsvf file
|
||||
doCOMMENTs = False # Save XCOMMENTs in the output xsvf file
|
||||
|
||||
# pick your file encoding
|
||||
file_encoding = 'ISO-8859-1'
|
||||
#file_encoding = 'utf-8'
|
||||
|
||||
|
||||
xrepeat = 0 # argument to XREPEAT, gives retry count for masked compares
|
||||
|
||||
|
||||
#-----< Lexer >---------------------------------------------------------------
|
||||
|
||||
StateBin = (RESET,IDLE,
|
||||
DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE,
|
||||
IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16)
|
||||
|
||||
# Any integer index into this tuple will be equal to its corresponding StateBin value
|
||||
StateTxt = ("RESET","IDLE",
|
||||
"DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE",
|
||||
"IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE")
|
||||
|
||||
|
||||
(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO,
|
||||
XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC,
|
||||
XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE,
|
||||
LCOUNT,LDELAY,LSDR,XTRST) = range(29)
|
||||
|
||||
#Note: LCOUNT, LDELAY, and LSDR are Lattice extensions to SVF and provide a way to loop back
|
||||
# and check a completion status, essentially waiting on a part until it signals that it is done.
|
||||
# For example below: loop 25 times, each time through the loop do a LDELAY (same as a true RUNTEST)
|
||||
# and exit loop when LSDR compares match.
|
||||
"""
|
||||
LCOUNT 25;
|
||||
! Step to DRPAUSE give 5 clocks and wait for 1.00e+000 SEC.
|
||||
LDELAY DRPAUSE 5 TCK 1.00E-003 SEC;
|
||||
! Test for the completed status. Match means pass.
|
||||
! Loop back to LDELAY line if not match and loop count less than 25.
|
||||
LSDR 1 TDI (0)
|
||||
TDO (1);
|
||||
"""
|
||||
|
||||
#XTRST is an opcode Xilinx seemed to have missed and it comes from the SVF TRST statement.
|
||||
|
||||
LineNumber = 1
|
||||
|
||||
def s_ident(scanner, token): return ("ident", token.upper(), LineNumber)
|
||||
|
||||
def s_hex(scanner, token):
|
||||
global LineNumber
|
||||
LineNumber = LineNumber + token.count('\n')
|
||||
token = ''.join(token.split())
|
||||
return ("hex", token[1:-1], LineNumber)
|
||||
|
||||
def s_int(scanner, token): return ("int", int(token), LineNumber)
|
||||
def s_float(scanner, token): return ("float", float(token), LineNumber)
|
||||
#def s_comment(scanner, token): return ("comment", token, LineNumber)
|
||||
def s_semicolon(scanner, token): return ("semi", token, LineNumber)
|
||||
|
||||
def s_nl(scanner,token):
|
||||
global LineNumber
|
||||
LineNumber = LineNumber + 1
|
||||
#print( 'LineNumber=', LineNumber, file=sys.stderr )
|
||||
return None
|
||||
|
||||
#2.00E-002
|
||||
|
||||
scanner = re.Scanner([
|
||||
(r"[a-zA-Z]\w*", s_ident),
|
||||
# (r"[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?", s_float),
|
||||
(r"[-+]?[0-9]+(([.][0-9eE+-]*)|([eE]+[-+]?[0-9]+))", s_float),
|
||||
(r"\d+", s_int),
|
||||
(r"\(([0-9a-fA-F]|\s)*\)", s_hex),
|
||||
(r"(!|//).*$", None),
|
||||
(r";", s_semicolon),
|
||||
(r"\n",s_nl),
|
||||
(r"\s*", None),
|
||||
],
|
||||
re.MULTILINE
|
||||
)
|
||||
|
||||
# open the file using the given encoding
|
||||
file = open( sys.argv[1], encoding=file_encoding )
|
||||
|
||||
# read all svf file input into string "input"
|
||||
input = file.read()
|
||||
|
||||
file.close()
|
||||
|
||||
# Lexer:
|
||||
# create a list of tuples containing (tokenType, tokenValue, LineNumber)
|
||||
tokens = scanner.scan( input )[0]
|
||||
|
||||
input = None # allow gc to reclaim memory holding file
|
||||
|
||||
#for tokenType, tokenValue, ln in tokens: print( "line %d: %s" % (ln, tokenType), tokenValue )
|
||||
|
||||
|
||||
#-----<parser>-----------------------------------------------------------------
|
||||
|
||||
tokVal = tokType = tokLn = None
|
||||
|
||||
tup = iter( tokens )
|
||||
|
||||
def nextTok():
|
||||
"""
|
||||
Function to read the next token from tup into tokType, tokVal, tokLn (linenumber)
|
||||
which are globals.
|
||||
"""
|
||||
global tokType, tokVal, tokLn, tup
|
||||
tokType, tokVal, tokLn = tup.__next__()
|
||||
|
||||
|
||||
class ParseError(Exception):
|
||||
"""A class to hold a parsing error message"""
|
||||
def __init__(self, linenumber, token, message):
|
||||
self.linenumber = linenumber
|
||||
self.token = token
|
||||
self.message = message
|
||||
def __str__(self):
|
||||
global inputFilename
|
||||
return "Error in file \'%s\' at line %d near token %s\n %s" % (
|
||||
inputFilename, self.linenumber, repr(self.token), self.message)
|
||||
|
||||
|
||||
class MASKSET(object):
|
||||
"""
|
||||
Class MASKSET holds a set of bit vectors, all of which are related, will all
|
||||
have the same length, and are associated with one of the seven shiftOps:
|
||||
HIR, HDR, TIR, TDR, SIR, SDR, LSDR. One of these holds a mask, smask, tdi, tdo, and a
|
||||
size.
|
||||
"""
|
||||
def __init__(self, name):
|
||||
self.empty()
|
||||
self.name = name
|
||||
|
||||
def empty(self):
|
||||
self.mask = bytearray()
|
||||
self.smask = bytearray()
|
||||
self.tdi = bytearray()
|
||||
self.tdo = bytearray()
|
||||
self.size = 0
|
||||
|
||||
def syncLengths( self, sawTDI, sawTDO, sawMASK, sawSMASK, newSize ):
|
||||
"""
|
||||
Set all the lengths equal in the event some of the masks were
|
||||
not seen as part of the last change set.
|
||||
"""
|
||||
if self.size == newSize:
|
||||
return
|
||||
|
||||
if newSize == 0:
|
||||
self.empty()
|
||||
return
|
||||
|
||||
# If an SIR was given without a MASK(), then use a mask of all zeros.
|
||||
# this is not consistent with the SVF spec, but it makes sense because
|
||||
# it would be odd to be testing an instruction register read out of a
|
||||
# tap without giving a mask for it. Also, lattice seems to agree and is
|
||||
# generating SVF files that comply with this philosophy.
|
||||
if self.name == 'SIR' and not sawMASK:
|
||||
self.mask = bytearray( newSize )
|
||||
|
||||
if newSize != len(self.mask):
|
||||
self.mask = bytearray( newSize )
|
||||
if self.name == 'SDR': # leave mask for HIR,HDR,TIR,TDR,SIR zeros
|
||||
for i in range( newSize ):
|
||||
self.mask[i] = 1
|
||||
|
||||
if newSize != len(self.tdo):
|
||||
self.tdo = bytearray( newSize )
|
||||
|
||||
if newSize != len(self.tdi):
|
||||
self.tdi = bytearray( newSize )
|
||||
|
||||
if newSize != len(self.smask):
|
||||
self.smask = bytearray( newSize )
|
||||
|
||||
self.size = newSize
|
||||
#-----</MASKSET>-----
|
||||
|
||||
|
||||
def makeBitArray( hexString, bitCount ):
|
||||
"""
|
||||
Converts a packed sequence of hex ascii characters into a bytearray where
|
||||
each element in the array holds exactly one bit. Only "bitCount" bits are
|
||||
scanned and these must be the least significant bits in the hex number. That
|
||||
is, it is legal to have some unused bits in the must significant hex nibble
|
||||
of the input "hexString". The string is scanned starting from the backend,
|
||||
then just before returning we reverse the array. This way the append()
|
||||
method can be used, which I assume is faster than an insert.
|
||||
"""
|
||||
global tokLn
|
||||
a = bytearray()
|
||||
length = bitCount
|
||||
hexString = list(hexString)
|
||||
hexString.reverse()
|
||||
#print(hexString)
|
||||
for c in hexString:
|
||||
if length <= 0:
|
||||
break;
|
||||
c = int(c, 16)
|
||||
for mask in [1,2,4,8]:
|
||||
if length <= 0:
|
||||
break;
|
||||
length = length - 1
|
||||
a.append( (c & mask) != 0 )
|
||||
if length > 0:
|
||||
raise ParseError( tokLn, hexString, "Insufficient hex characters for given length of %d" % bitCount )
|
||||
a.reverse()
|
||||
#print(a)
|
||||
return a
|
||||
|
||||
|
||||
def makeXSVFbytes( bitarray ):
|
||||
"""
|
||||
Make a bytearray which is contains the XSVF bits which will be written
|
||||
directly to disk. The number of bytes needed is calculated from the size
|
||||
of the argument bitarray.
|
||||
"""
|
||||
bitCount = len(bitarray)
|
||||
byteCount = (bitCount+7)//8
|
||||
ba = bytearray( byteCount )
|
||||
firstBit = (bitCount % 8) - 1
|
||||
if firstBit == -1:
|
||||
firstBit = 7
|
||||
bitNdx = 0
|
||||
for byteNdx in range(byteCount):
|
||||
mask = 1<<firstBit
|
||||
byte = 0
|
||||
while mask:
|
||||
if bitarray[bitNdx]:
|
||||
byte |= mask;
|
||||
mask = mask >> 1
|
||||
bitNdx = bitNdx + 1
|
||||
ba[byteNdx] = byte
|
||||
firstBit = 7
|
||||
return ba
|
||||
|
||||
|
||||
def writeComment( outputFile, shiftOp_linenum, shiftOp ):
|
||||
"""
|
||||
Write an XCOMMENT record to outputFile
|
||||
"""
|
||||
comment = "%s @%d\0" % (shiftOp, shiftOp_linenum) # \0 is terminating nul
|
||||
ba = bytearray(1)
|
||||
ba[0] = XCOMMENT
|
||||
ba += comment.encode()
|
||||
outputFile.write( ba )
|
||||
|
||||
|
||||
def combineBitVectors( trailer, meat, header ):
|
||||
"""
|
||||
Combine the 3 bit vectors comprizing a transmission. Since the least
|
||||
significant bits are sent first, the header is put onto the list last so
|
||||
they are sent first from that least significant position.
|
||||
"""
|
||||
ret = bytearray()
|
||||
ret.extend( trailer )
|
||||
ret.extend( meat )
|
||||
ret.extend( header )
|
||||
return ret
|
||||
|
||||
|
||||
def writeRUNTEST( outputFile, run_state, end_state, run_count, min_time, tokenTxt ):
|
||||
"""
|
||||
Write the output for the SVF RUNTEST command.
|
||||
run_count - the number of clocks
|
||||
min_time - the number of seconds
|
||||
tokenTxt - either RUNTEST or LDELAY
|
||||
"""
|
||||
# convert from secs to usecs
|
||||
min_time = int( min_time * 1000000)
|
||||
|
||||
# the SVF RUNTEST command does NOT map to the XSVF XRUNTEST command. Check the SVF spec, then
|
||||
# read the XSVF command. They are not the same. Use an XSVF XWAITSTATE to
|
||||
# implement the required behavior of the SVF RUNTEST command.
|
||||
if doCOMMENTs:
|
||||
writeComment( output, tokLn, tokenTxt )
|
||||
|
||||
if tokenTxt == 'RUNTEST':
|
||||
obuf = bytearray(11)
|
||||
obuf[0] = XWAITSTATE
|
||||
obuf[1] = run_state
|
||||
obuf[2] = end_state
|
||||
struct.pack_into(">i", obuf, 3, run_count ) # big endian 4 byte int to obuf
|
||||
struct.pack_into(">i", obuf, 7, min_time ) # big endian 4 byte int to obuf
|
||||
outputFile.write( obuf )
|
||||
else: # == 'LDELAY'
|
||||
obuf = bytearray(10)
|
||||
obuf[0] = LDELAY
|
||||
obuf[1] = run_state
|
||||
# LDELAY has no end_state
|
||||
struct.pack_into(">i", obuf, 2, run_count ) # big endian 4 byte int to obuf
|
||||
struct.pack_into(">i", obuf, 6, min_time ) # big endian 4 byte int to obuf
|
||||
outputFile.write( obuf )
|
||||
|
||||
|
||||
output = open( outputFilename, mode='wb' )
|
||||
|
||||
hir = MASKSET('HIR')
|
||||
hdr = MASKSET('HDR')
|
||||
tir = MASKSET('TIR')
|
||||
tdr = MASKSET('TDR')
|
||||
sir = MASKSET('SIR')
|
||||
sdr = MASKSET('SDR')
|
||||
|
||||
|
||||
expecting_eof = True
|
||||
|
||||
|
||||
# one of the commands that take the shiftParts after the length, the parse
|
||||
# template for all of these commands is identical
|
||||
shiftOps = ('SDR', 'SIR', 'LSDR', 'HDR', 'HIR', 'TDR', 'TIR')
|
||||
|
||||
# the order must correspond to shiftOps, this holds the MASKSETS. 'LSDR' shares sdr with 'SDR'
|
||||
shiftSets = (sdr, sir, sdr, hdr, hir, tdr, tir )
|
||||
|
||||
# what to expect as parameters to a shiftOp, i.e. after a SDR length or SIR length
|
||||
shiftParts = ('TDI', 'TDO', 'MASK', 'SMASK')
|
||||
|
||||
# the set of legal states which can trail the RUNTEST command
|
||||
run_state_allowed = ('IRPAUSE', 'DRPAUSE', 'RESET', 'IDLE')
|
||||
|
||||
enddr_state_allowed = ('DRPAUSE', 'IDLE')
|
||||
endir_state_allowed = ('IRPAUSE', 'IDLE')
|
||||
|
||||
trst_mode_allowed = ('ON', 'OFF', 'Z', 'ABSENT')
|
||||
|
||||
enddr_state = IDLE
|
||||
endir_state = IDLE
|
||||
|
||||
frequency = 1.00e+006 # HZ;
|
||||
|
||||
# change detection for xsdrsize and xtdomask
|
||||
xsdrsize = -1 # the last one sent, send only on change
|
||||
xtdomask = bytearray() # the last one sent, send only on change
|
||||
|
||||
|
||||
# we use a number of single byte writes for the XSVF command below
|
||||
cmdbuf = bytearray(1)
|
||||
|
||||
|
||||
# Save the XREPEAT setting into the file as first thing.
|
||||
obuf = bytearray(2)
|
||||
obuf[0] = XREPEAT
|
||||
obuf[1] = xrepeat
|
||||
output.write( obuf )
|
||||
|
||||
|
||||
try:
|
||||
while 1:
|
||||
expecting_eof = True
|
||||
nextTok()
|
||||
expecting_eof = False
|
||||
# print( tokType, tokVal, tokLn )
|
||||
|
||||
if tokVal in shiftOps:
|
||||
shiftOp_linenum = tokLn
|
||||
shiftOp = tokVal
|
||||
|
||||
set = shiftSets[shiftOps.index(shiftOp)]
|
||||
|
||||
# set flags false, if we see one later, set that one true later
|
||||
sawTDI = sawTDO = sawMASK = sawSMASK = False
|
||||
|
||||
nextTok()
|
||||
if tokType != 'int':
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'int' giving %s length, got '%s'" % (shiftOp, tokType) )
|
||||
length = tokVal
|
||||
|
||||
nextTok()
|
||||
|
||||
while tokVal != ';':
|
||||
if tokVal not in shiftParts:
|
||||
raise ParseError( tokLn, tokVal, "Expecting TDI, TDO, MASK, SMASK, or ';'")
|
||||
shiftPart = tokVal
|
||||
|
||||
nextTok()
|
||||
|
||||
if tokType != 'hex':
|
||||
raise ParseError( tokLn, tokVal, "Expecting hex bits" )
|
||||
bits = makeBitArray( tokVal, length )
|
||||
|
||||
if shiftPart == 'TDI':
|
||||
sawTDI = True
|
||||
set.tdi = bits
|
||||
|
||||
elif shiftPart == 'TDO':
|
||||
sawTDO = True
|
||||
set.tdo = bits
|
||||
|
||||
elif shiftPart == 'MASK':
|
||||
sawMASK = True
|
||||
set.mask = bits
|
||||
|
||||
elif shiftPart == 'SMASK':
|
||||
sawSMASK = True
|
||||
set.smask = bits
|
||||
|
||||
nextTok()
|
||||
|
||||
set.syncLengths( sawTDI, sawTDO, sawMASK, sawSMASK, length )
|
||||
|
||||
# process all the gathered parameters and generate outputs here
|
||||
if shiftOp == 'SIR':
|
||||
if doCOMMENTs:
|
||||
writeComment( output, shiftOp_linenum, 'SIR' )
|
||||
|
||||
tdi = combineBitVectors( tir.tdi, sir.tdi, hir.tdi )
|
||||
if len(tdi) > 255:
|
||||
obuf = bytearray(3)
|
||||
obuf[0] = XSIR2
|
||||
struct.pack_into( ">h", obuf, 1, len(tdi) )
|
||||
else:
|
||||
obuf = bytearray(2)
|
||||
obuf[0] = XSIR
|
||||
obuf[1] = len(tdi)
|
||||
output.write( obuf )
|
||||
obuf = makeXSVFbytes( tdi )
|
||||
output.write( obuf )
|
||||
|
||||
elif shiftOp == 'SDR':
|
||||
if doCOMMENTs:
|
||||
writeComment( output, shiftOp_linenum, shiftOp )
|
||||
|
||||
if not sawTDO:
|
||||
# pass a zero filled bit vector for the sdr.mask
|
||||
mask = combineBitVectors( tdr.mask, bytearray(sdr.size), hdr.mask )
|
||||
tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi )
|
||||
|
||||
if xsdrsize != len(tdi):
|
||||
xsdrsize = len(tdi)
|
||||
cmdbuf[0] = XSDRSIZE
|
||||
output.write( cmdbuf )
|
||||
obuf = bytearray(4)
|
||||
struct.pack_into( ">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf
|
||||
output.write( obuf )
|
||||
|
||||
if xtdomask != mask:
|
||||
xtdomask = mask
|
||||
cmdbuf[0] = XTDOMASK
|
||||
output.write( cmdbuf )
|
||||
obuf = makeXSVFbytes( mask )
|
||||
output.write( obuf )
|
||||
|
||||
cmdbuf[0] = XSDR
|
||||
output.write( cmdbuf )
|
||||
obuf = makeXSVFbytes( tdi )
|
||||
output.write( obuf )
|
||||
|
||||
else:
|
||||
mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask )
|
||||
tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi )
|
||||
tdo = combineBitVectors( tdr.tdo, sdr.tdo, hdr.tdo )
|
||||
|
||||
if xsdrsize != len(tdi):
|
||||
xsdrsize = len(tdi)
|
||||
cmdbuf[0] = XSDRSIZE
|
||||
output.write( cmdbuf )
|
||||
obuf = bytearray(4)
|
||||
struct.pack_into(">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf
|
||||
output.write( obuf )
|
||||
|
||||
if xtdomask != mask:
|
||||
xtdomask = mask
|
||||
cmdbuf[0] = XTDOMASK
|
||||
output.write( cmdbuf )
|
||||
obuf = makeXSVFbytes( mask )
|
||||
output.write( obuf )
|
||||
|
||||
cmdbuf[0] = XSDRTDO
|
||||
output.write( cmdbuf )
|
||||
obuf = makeXSVFbytes( tdi )
|
||||
output.write( obuf )
|
||||
obuf = makeXSVFbytes( tdo )
|
||||
output.write( obuf )
|
||||
#print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) )
|
||||
|
||||
elif shiftOp == 'LSDR':
|
||||
if doCOMMENTs:
|
||||
writeComment( output, shiftOp_linenum, shiftOp )
|
||||
|
||||
mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask )
|
||||
tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi )
|
||||
tdo = combineBitVectors( tdr.tdo, sdr.tdo, hdr.tdo )
|
||||
|
||||
if xsdrsize != len(tdi):
|
||||
xsdrsize = len(tdi)
|
||||
cmdbuf[0] = XSDRSIZE
|
||||
output.write( cmdbuf )
|
||||
obuf = bytearray(4)
|
||||
struct.pack_into(">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf
|
||||
output.write( obuf )
|
||||
|
||||
if xtdomask != mask:
|
||||
xtdomask = mask
|
||||
cmdbuf[0] = XTDOMASK
|
||||
output.write( cmdbuf )
|
||||
obuf = makeXSVFbytes( mask )
|
||||
output.write( obuf )
|
||||
|
||||
cmdbuf[0] = LSDR
|
||||
output.write( cmdbuf )
|
||||
obuf = makeXSVFbytes( tdi )
|
||||
output.write( obuf )
|
||||
obuf = makeXSVFbytes( tdo )
|
||||
output.write( obuf )
|
||||
#print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) )
|
||||
|
||||
elif tokVal == 'RUNTEST' or tokVal == 'LDELAY':
|
||||
# e.g. from lattice tools:
|
||||
# "RUNTEST IDLE 5 TCK 1.00E-003 SEC;"
|
||||
saveTok = tokVal
|
||||
nextTok()
|
||||
min_time = 0
|
||||
run_count = 0
|
||||
max_time = 600 # ten minutes
|
||||
if tokVal in run_state_allowed:
|
||||
run_state = StateTxt.index(tokVal)
|
||||
end_state = run_state # bottom of page 17 of SVF spec
|
||||
nextTok()
|
||||
if tokType != 'int' and tokType != 'float':
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'int' or 'float' after RUNTEST [run_state]")
|
||||
timeval = tokVal;
|
||||
nextTok()
|
||||
if tokVal != 'TCK' and tokVal != 'SEC' and tokVal != 'SCK':
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'TCK' or 'SEC' or 'SCK' after RUNTEST [run_state] (run_count|min_time)")
|
||||
if tokVal == 'TCK' or tokVal == 'SCK':
|
||||
run_count = int( timeval )
|
||||
else:
|
||||
min_time = timeval
|
||||
nextTok()
|
||||
if tokType == 'int' or tokType == 'float':
|
||||
min_time = tokVal
|
||||
nextTok()
|
||||
if tokVal != 'SEC':
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'SEC' after RUNTEST [run_state] run_count min_time")
|
||||
nextTok()
|
||||
if tokVal == 'MAXIMUM':
|
||||
nextTok()
|
||||
if tokType != 'int' and tokType != 'float':
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM")
|
||||
max_time = tokVal
|
||||
nextTok()
|
||||
if tokVal != 'SEC':
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM max_time")
|
||||
nextTok()
|
||||
if tokVal == 'ENDSTATE':
|
||||
nextTok()
|
||||
if tokVal not in run_state_allowed:
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'run_state' after RUNTEST .... ENDSTATE")
|
||||
end_state = StateTxt.index(tokVal)
|
||||
nextTok()
|
||||
if tokVal != ';':
|
||||
raise ParseError( tokLn, tokVal, "Expecting ';' after RUNTEST ....")
|
||||
# print( "run_count=", run_count, "min_time=", min_time,
|
||||
# "max_time=", max_time, "run_state=", State[run_state], "end_state=", State[end_state] )
|
||||
writeRUNTEST( output, run_state, end_state, run_count, min_time, saveTok )
|
||||
|
||||
elif tokVal == 'LCOUNT':
|
||||
nextTok()
|
||||
if tokType != 'int':
|
||||
raise ParseError( tokLn, tokVal, "Expecting integer 'count' after LCOUNT")
|
||||
loopCount = tokVal
|
||||
nextTok()
|
||||
if tokVal != ';':
|
||||
raise ParseError( tokLn, tokVal, "Expecting ';' after LCOUNT count")
|
||||
if doCOMMENTs:
|
||||
writeComment( output, tokLn, 'LCOUNT' )
|
||||
obuf = bytearray(5)
|
||||
obuf[0] = LCOUNT
|
||||
struct.pack_into(">i", obuf, 1, loopCount ) # big endian 4 byte int to obuf
|
||||
output.write( obuf )
|
||||
|
||||
elif tokVal == 'ENDDR':
|
||||
nextTok()
|
||||
if tokVal not in enddr_state_allowed:
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDDR. (one of: DRPAUSE, IDLE)")
|
||||
enddr_state = StateTxt.index(tokVal)
|
||||
nextTok()
|
||||
if tokVal != ';':
|
||||
raise ParseError( tokLn, tokVal, "Expecting ';' after ENDDR stable_state")
|
||||
if doCOMMENTs:
|
||||
writeComment( output, tokLn, 'ENDDR' )
|
||||
obuf = bytearray(2)
|
||||
obuf[0] = XENDDR
|
||||
# Page 10 of the March 1999 SVF spec shows that RESET is also allowed here.
|
||||
# Yet the XSVF spec has no provision for that, and uses a non-standard, i.e.
|
||||
# boolean argument to XENDDR which only handles two of the 3 intended states.
|
||||
obuf[1] = 1 if enddr_state == DRPAUSE else 0
|
||||
output.write( obuf )
|
||||
|
||||
elif tokVal == 'ENDIR':
|
||||
nextTok()
|
||||
if tokVal not in endir_state_allowed:
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDIR. (one of: IRPAUSE, IDLE)")
|
||||
endir_state = StateTxt.index(tokVal)
|
||||
nextTok()
|
||||
if tokVal != ';':
|
||||
raise ParseError( tokLn, tokVal, "Expecting ';' after ENDIR stable_state")
|
||||
if doCOMMENTs:
|
||||
writeComment( output, tokLn, 'ENDIR' )
|
||||
obuf = bytearray(2)
|
||||
obuf[0] = XENDIR
|
||||
# Page 10 of the March 1999 SVF spec shows that RESET is also allowed here.
|
||||
# Yet the XSVF spec has no provision for that, and uses a non-standard, i.e.
|
||||
# boolean argument to XENDDR which only handles two of the 3 intended states.
|
||||
obuf[1] = 1 if endir_state == IRPAUSE else 0
|
||||
output.write( obuf )
|
||||
|
||||
elif tokVal == 'STATE':
|
||||
nextTok()
|
||||
ln = tokLn
|
||||
while tokVal != ';':
|
||||
if tokVal not in StateTxt:
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after STATE")
|
||||
stable_state = StateTxt.index( tokVal )
|
||||
|
||||
if doCOMMENTs and ln != -1:
|
||||
writeComment( output, ln, 'STATE' )
|
||||
ln = -1 # save comment only once
|
||||
|
||||
obuf = bytearray(2)
|
||||
obuf[0] = XSTATE
|
||||
obuf[1] = stable_state
|
||||
output.write( obuf )
|
||||
nextTok()
|
||||
|
||||
elif tokVal == 'FREQUENCY':
|
||||
nextTok()
|
||||
if tokVal != ';':
|
||||
if tokType != 'int' and tokType != 'float':
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'cycles HZ' after FREQUENCY")
|
||||
frequency = tokVal
|
||||
nextTok()
|
||||
if tokVal != 'HZ':
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'HZ' after FREQUENCY cycles")
|
||||
nextTok()
|
||||
if tokVal != ';':
|
||||
raise ParseError( tokLn, tokVal, "Expecting ';' after FREQUENCY cycles HZ")
|
||||
|
||||
elif tokVal == 'TRST':
|
||||
nextTok()
|
||||
if tokVal not in trst_mode_allowed:
|
||||
raise ParseError( tokLn, tokVal, "Expecting 'ON|OFF|Z|ABSENT' after TRST")
|
||||
trst_mode = tokVal
|
||||
nextTok()
|
||||
if tokVal != ';':
|
||||
raise ParseError( tokLn, tokVal, "Expecting ';' after TRST trst_mode")
|
||||
if doCOMMENTs:
|
||||
writeComment( output, tokLn, 'TRST %s' % trst_mode )
|
||||
obuf = bytearray( 2 )
|
||||
obuf[0] = XTRST
|
||||
obuf[1] = trst_mode_allowed.index( trst_mode ) # use the index as the binary argument to XTRST opcode
|
||||
output.write( obuf )
|
||||
|
||||
else:
|
||||
raise ParseError( tokLn, tokVal, "Unknown token '%s'" % tokVal)
|
||||
|
||||
except StopIteration:
|
||||
if not expecting_eof:
|
||||
print( "Unexpected End of File at line ", tokLn )
|
||||
|
||||
except ParseError as pe:
|
||||
print( "\n", pe )
|
||||
|
||||
finally:
|
||||
# print( "closing file" )
|
||||
cmdbuf[0] = XCOMPLETE
|
||||
output.write( cmdbuf )
|
||||
output.close()
|
||||
|