{"id":51475118,"url":"https://github.com/jbilander/par2ser","last_synced_at":"2026-07-06T20:01:16.283Z","repository":{"id":361802248,"uuid":"1246517392","full_name":"jbilander/Par2Ser","owner":"jbilander","description":"A device that bridges the Amiga parallel port to a USB FIFO (FT240X)","archived":false,"fork":false,"pushed_at":"2026-07-04T11:43:27.000Z","size":8874,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T13:15:19.635Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc-by-sa-4.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jbilander.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-22T09:15:05.000Z","updated_at":"2026-07-04T11:43:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jbilander/Par2Ser","commit_stats":null,"previous_names":["jbilander/par2ser"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jbilander/Par2Ser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbilander%2FPar2Ser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbilander%2FPar2Ser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbilander%2FPar2Ser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbilander%2FPar2Ser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jbilander","download_url":"https://codeload.github.com/jbilander/Par2Ser/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbilander%2FPar2Ser/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35204409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-06T20:01:15.053Z","updated_at":"2026-07-06T20:01:16.263Z","avatar_url":"https://github.com/jbilander.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Amiga Par2Ser device\n\n\u003e 🚧 **Status: Work-in-progress — bidirectional link verified on real Rev 2A\n\u003e hardware.** Both directions work end-to-end: characters typed on the Amiga\n\u003e in c-kermit appear on the PC over the FT240X's USB serial port, and\n\u003e characters typed on the PC appear in c-kermit on the Amiga. **Kermit file\n\u003e transfers do not succeed yet** — interactive traffic is solid, but protocol\n\u003e transfers (`send`/`rdir`) currently fail with retries; packet-burst\n\u003e handling is the next debugging target. There are no tagged releases until\n\u003e file transfer works, so **build at your own risk** and expect the design to\n\u003e still change. PRs and issues welcome.\n\n***\nRev. 2A \u003cbr /\u003e\n\u003ca href=\"images/Par2Ser_rev2A_pic1.png\"\u003e\n\u003cimg src=\"images/Par2Ser_rev2A_pic1.png\" width=\"600\" height=\"609\"\u003e\n\u003c/a\u003e\n\n***\n\nA `serial.device`-compatible Amiga driver that bridges the parallel port to a\nUSB FIFO (FT240X) via Niklas Ekström's 2E parallel-adapter protocol, so unmodified\ncomms programs (c-kermit, NComm, …) can `set line par2ser.device`.\n\nThe hardware side is a small board built around a Lattice **LC4064V-75TN48C**\nCPLD that speaks the 2E protocol to the Amiga and presents the bytes to an\n**FT240X** USB FIFO. The PC sees a standard USB serial port (VCP).\n\n## Repository layout\n\n- **`amiga/`** — `par2ser.device` driver source (m68k, Bartman gcc).\n- **`cpld/`** — Verilog firmware for the Lattice LC4064V CPLD.\n  - `rtl/` — design sources (`par2ser_top.v`, `par2ser_fsm.v`).\n  - `sim/` — Icarus Verilog smoke testbench.\n  - `isplever/` — Lattice ispLEVER Classic 2.1 project files and pin\n    constraints (`Par2Ser.lci`).\n- **`KiCad/`** — KiCad 5.1 schematic and PCB sources (Rev 2A).\n- **`FT_PROG/`** — FT_PROG template (`Par2Ser.xml`) capturing the\n  FT240X MTP settings the bridge needs (VCP enabled, CBUS5 → CLK12MHz,\n  product description). Open it in FT_PROG and apply to a fresh\n  board to skip the manual click-through.\n- **`images/`** — board photos and screenshots used in this README.\n- **`Par2Ser_rev2a_schematic.pdf`** — exported schematic for quick\n  reference without opening KiCad.\n\n## Hardware overview (Rev 2A)\n\n- **Lattice LC4064V-75TN48C** CPLD (48-pin TQFP, 64 macrocells, -75 speed)\n- **FTDI FT240X** USB-to-parallel-FIFO (SSOP-24), USB-C connector\n- **8-bit bidirectional buffer** between the Amiga DB-25 and the CPLD\n- **JTAG header** for programming the CPLD via ispVM System with a\n  cheap FT4232H-mini-module-based cable\n\nThe driver is built in the style of [SimpleDevice](https://github.com/jbilander/SimpleDevice)\nfor the Bartman `m68k-amiga-elf` (gcc 15.1) toolchain. The serial machinery\n(receive ring buffer, `CMD_READ` satisfied from buffer, `SDCMD_QUERY` count\nfrom a software counter) is ported from Iain Barclay's `8n1.device` 43.5.\n\nIt targets **Kickstart 1.3** (and up): the sources include `\u003cks13_compat.h\u003e`,\nwhich uses `#pragma GCC poison` to turn any accidental call to a KS 2.0+\nlibrary function into a compile error, so the driver stays loadable on an\nunexpanded A500/A2000.\n\n## Bill of Materials (Rev 2A)\n\nSourcing notes: most actives and precision passives are from\n[Mouser](https://www.mouser.com/), the connectors and decorative\nLEDs are inexpensive enough to come from AliExpress sellers (linked\nexamples below — any equivalent footprint works). Generic 0805/0603\npassives can be substituted with any reputable manufacturer's part\nmatching the value, package, and dielectric/tolerance noted.\n\n| Ref               | Qty | Value / Part         | Description                                    | Package        | Source                                                                                          | Notes                                                       |\n|-------------------|-----|----------------------|------------------------------------------------|----------------|-------------------------------------------------------------------------------------------------|-------------------------------------------------------------|\n| **U1**            | 1   | LC4064V-75TN48C      | Lattice ispMACH 4000V CPLD                     | 48-TQFP        | [Mouser 842-LC4064V75TN48C](https://www.mouser.com/ProductDetail/842-LC4064V75TN48C)             | 64 macrocells, -75 speed grade                              |\n| **U2**            | 1   | FT240XS-R            | FTDI USB-to-parallel FIFO                      | SSOP-24        | [Mouser 895-FT240XS-R](https://www.mouser.com/ProductDetail/895-FT240XS-R)                       | USB 2.0 Full Speed; VCP driver                              |\n| **U3**            | 1   | TLV75533PDBVR        | TI 3.3 V LDO regulator, 500 mA                 | SOT-23-5       | [Mouser 595-TLV75533PDBVR](https://www.mouser.com/ProductDetail/595-TLV75533PDBVR)               | Fixed 3.3 V output                                          |\n| **J1**            | 1   | DB25 Male            | Right-angle PCB DB-25 (M)                      | Solder cups   | [AliExpress example](https://www.aliexpress.com/item/1005006354086316.html)                      | Amiga parallel port                                         |\n| **J2**            | 1   | USB-C 2.0 (TYPE-C-02) | 16-pin USB-C, USB 2.0 only (no SuperSpeed)    | SMD + THM tabs | [AliExpress example](https://www.aliexpress.com/item/1005005371954812.html)                      | Common \"TYPE-C-02\" footprint                                |\n| **J3**            | 1   | 2×5 pin header       | 2.54 mm pitch, 10-pin (2×5)                    | Through-hole   | [AliExpress example](https://www.aliexpress.com/item/1005001493183557.html)                      | Optional — can press-fit ribbon during programming          |\n| **FB1**           | 1   | 600 Ω @ 100 MHz       | Ferrite bead                                   | 0805           | [Mouser 875-HZ0805E601R-10](https://www.mouser.com/ProductDetail/875-HZ0805E601R-10)              | USB VBUS filter                                             |\n| **D1**            | 1   | Yellow LED           | Activity LED (optional)                        | 2×5×7 mm TH    | [AliExpress example](https://www.aliexpress.com/item/1005006220921860.html)                      | Lit when transaction in progress                            |\n| **D2**            | 1   | Green LED            | Power LED (optional)                           | 2×5×7 mm TH    | [AliExpress example](https://www.aliexpress.com/item/1005006220921860.html)                      | 3.3 V rail indicator                                        |\n| **D3**            | 1   | Red LED              | TX LED                                         | 0603 SMD       | [AliExpress example](https://www.aliexpress.com/item/1005005975741298.html)                      | Amiga → PC byte flow                                        |\n| **D4**            | 1   | Red LED              | RX LED                                         | 0603 SMD       | [AliExpress example](https://www.aliexpress.com/item/1005005975741298.html)                      | PC → Amiga byte flow                                        |\n| **RN1**           | 1   | 8×10 kΩ bussed (A09-103JP) | 9-pin SIP resistor network               | SIP-9          | [AliExpress example](https://www.aliexpress.com/item/1005006954621214.html)                      | Amiga D0..D7 pull-ups, one common                           |\n| **RN2**           | 1   | 4×10 kΩ bussed (A05-103JP) | 5-pin SIP resistor network               | SIP-5          | [AliExpress example](https://www.aliexpress.com/item/1005006954621214.html)                      | Additional Amiga-side pull-ups                              |\n| **RN3, RN4, RN5** | 3   | 4×330 Ω isolated     | 8-pin SMD isolated resistor array              | 1206-8         | [Mouser 652-CAY16-3300F4LF](https://www.mouser.com/ProductDetail/652-CAY16-3300F4LF)              | Series limiters on signal lines                             |\n| **R1, R3, R4**    | 3   | 1 kΩ                 | LED current limiter / signal                   | 0805           | [Mouser 652-CR0805FX-1001ELF](https://www.mouser.com/ProductDetail/652-CR0805FX-1001ELF)          |                                                             |\n| **R2**            | 1   | 10 kΩ                | Series for D2 power LED (high R = low brightness) | 0805        | [Mouser 652-CR0805FX-1002ELF](https://www.mouser.com/ProductDetail/652-CR0805FX-1002ELF)          | Matches green power-LED forward voltage                     |\n| **R5**            | 1   | 33 Ω                 | CLKOUT line damping resistor                   | 0603           | [Mouser 652-CR0603FX-33R0ELF](https://www.mouser.com/ProductDetail/652-CR0603FX-33R0ELF)          | Common practice for clock lines, not per FT240X datasheet  |\n| **R6**            | 0   | 330 Ω (**DNP**)      | Series on /STROBE — not populated              | 0805           | [Mouser 652-CR0805FX-3300ELF](https://www.mouser.com/ProductDetail/652-CR0805FX-3300ELF)          | **Do Not Place** — populate only if /STROBE used in fw      |\n| **R7, R8**        | 2   | 5.1 kΩ               | USB-C CC1/CC2 pull-downs                       | 0805           | [Mouser 652-CR0805FX-5101ELF](https://www.mouser.com/ProductDetail/652-CR0805FX-5101ELF)          | Identifies device as USB 2.0 (sink)                         |\n| **R9, R10**       | 2   | 27 Ω                 | USB D+/D− series                               | 0805           | [Mouser 652-CR0805FX-27R0ELF](https://www.mouser.com/ProductDetail/652-CR0805FX-27R0ELF)          | Per USB 2.0 Full Speed spec                                 |\n| **R11**           | 1   | 4.7 kΩ               | Pull-down for TCK (JTAG)                       | 0805           | [Mouser 652-CR0805FX-4701ELF](https://www.mouser.com/ProductDetail/652-CR0805FX-4701ELF)          | Standard JTAG practice                                      |\n| **R12**           | 1   | 10 kΩ                | Pull-up for SIWU#                              | 0603           | [Mouser 652-CR0603-JW-103ELF](https://www.mouser.com/ProductDetail/652-CR0603-JW-103ELF)          | Keeps SIWU# deasserted when CPLD pin 44 is high-Z           |\n| **C1, C2**        | 2   | 4.7 µF, 10 V, X7R    | VBUS bulk / LDO input                          | 0805           | [Mouser 81-GRM21BR71A475KE1K](https://www.mouser.com/ProductDetail/81-GRM21BR71A475KE1K)          | Murata GRM21 X7R, 10 V                                      |\n| **C3**            | 1   | 1 µF, X7R            | LDO output filter                              | 0805           |                                                                                                 | Per TLV75533 datasheet                                      |\n| **C4, C5**        | 2   | 47 pF, C0G/NP0       | USB D+/D− noise filter                         | 0603           | [Mouser 791-0603N470G160CT](https://www.mouser.com/ProductDetail/791-0603N470G160CT)              | Tight tolerance important                                   |\n| **C6, C7, C8**    | 3   | 0.1 µF, X7R          | Decoupling (0805 spots)                        | 0805           |                                                                                                 |                                                             |\n| **C9 – C13**      | 5   | 0.1 µF, X7R          | Decoupling (0603 spots)                        | 0603           |                                                                                                 | One per VCC pin                                             |\n\n**Distinct line items: 27** \u0026nbsp;·\u0026nbsp; **Components to populate: 37** (38 if /STROBE is wired up in a future firmware — see R6)\n\n### Mounting and additional hardware\n\n- The **LC4064V** is JTAG-programmable in-circuit — no socket needed.\n- The **JTAG header (J3)** uses the standard Lattice 2×5 pinout —\n  check `cpld/README.md` for the exact pinout and the recommended\n  FT4232H-Mini-Module-based cable. The header doesn't have to be\n  soldered down; you can press-and-hold the 2×5 ribbon cable\n  against the pads during programming.\n\n### 3D-printable case\n\nA 3D-printable two-part case is provided in the `3D/` folder. It is\nadapted from the former **SDBox-v2** case, slimmed down and made more\nproportional — the Rev 2A design no longer has to house a bulky\nArduino Nano v3, so the enclosure is significantly thinner. The DB-25\nexits one end and the USB-C port the other, and the top lid has two\nholes for the panel LEDs: one for the **Power LED (green)** and one for\nthe **Activity LED (yellow)**.\n\n| File | Description |\n|------|-------------|\n| `3D/Par2Ser.scdoc` | SpaceClaim source file for the case |\n| `3D/Par2Ser.stp` | STEP export (top + bottom) for use in other CAD tools |\n| `3D/Par2Ser_top.stl` | Top lid, ready to slice and print |\n| `3D/Par2Ser_bottom.stl` | Bottom shell, ready to slice and print |\n| `3D/Par2Ser_text.skp` | SketchUp source for the embossed \"Par2Ser\" lid text |\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"images/Par2Ser_case_pic3.png\"\u003e\n        \u003cimg src=\"images/Par2Ser_case_pic3.png\" width=\"380\"\u003e\n      \u003c/a\u003e\u003cbr /\u003e\n      \u003csub\u003eUSB-C end, with the two LED holes in the top lid\u003c/sub\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"images/Par2Ser_case_pic1.png\"\u003e\n        \u003cimg src=\"images/Par2Ser_case_pic1.png\" width=\"380\"\u003e\n      \u003c/a\u003e\u003cbr /\u003e\n      \u003csub\u003eDB-25 end\u003c/sub\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"images/Par2Ser_case_pic4.png\"\u003e\n        \u003cimg src=\"images/Par2Ser_case_pic4.png\" width=\"380\"\u003e\n      \u003c/a\u003e\u003cbr /\u003e\n      \u003csub\u003eSide profile showing the slimmer enclosure\u003c/sub\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"images/Par2Ser_case_pic2.png\"\u003e\n        \u003cimg src=\"images/Par2Ser_case_pic2.png\" width=\"380\"\u003e\n      \u003c/a\u003e\u003cbr /\u003e\n      \u003csub\u003ePCB fitted into the bottom shell\u003c/sub\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nThe renders above are from the CAD program. The case was printed on a\nCreality Ender-3 Pro in white PLA. The build photos below show the\nassembly steps and the finished unit fitted to an Amiga 500.\n\n#### Fitting the panel LEDs\n\nThe two indicator LEDs are soldered last. Fit the **PWR (green, Power)**\nand **ACT (yellow, Activity)** LEDs into their positions, then check\nfrom the top that each one protrudes ever so slightly through its hole\nin the case lid. Once the height looks right, tack down a single leg,\nsnip the leads flush, and only then solder both joints properly. Doing\nit in that order keeps the LEDs sitting at the correct height instead of\nbeing pushed in or standing too proud.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"images/Par2Ser_soldering_PWR_and_ACT_LEDs.jpg\"\u003e\n        \u003cimg src=\"images/Par2Ser_soldering_PWR_and_ACT_LEDs.jpg\" width=\"380\"\u003e\n      \u003c/a\u003e\u003cbr /\u003e\n      \u003csub\u003eTest-fitting the green PWR and yellow ACT LEDs before tacking them down\u003c/sub\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"images/Par2Ser_soldering_completed.jpg\"\u003e\n        \u003cimg src=\"images/Par2Ser_soldering_completed.jpg\" width=\"380\"\u003e\n      \u003c/a\u003e\u003cbr /\u003e\n      \u003csub\u003eUnderside of the finished board seated in the bottom shell\u003c/sub\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n#### Finished unit\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"images/Par2Ser_installed_in_case.jpg\"\u003e\n        \u003cimg src=\"images/Par2Ser_installed_in_case.jpg\" width=\"380\"\u003e\n      \u003c/a\u003e\u003cbr /\u003e\n      \u003csub\u003eAssembled case closed up, with the PWR/ACT LEDs visible through the lid\u003c/sub\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"images/Par2Ser_installed_in_A500_and_connected_to_PC.jpg\"\u003e\n        \u003cimg src=\"images/Par2Ser_installed_in_A500_and_connected_to_PC.jpg\" width=\"380\"\u003e\n      \u003c/a\u003e\u003cbr /\u003e\n      \u003csub\u003ePlugged into the A500 parallel port and connected to a PC over USB-C\u003c/sub\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nIn the powered-on photo the green **PWR** LED is lit, and the red glow\nbleeding through the lid is the FT240XS **RX/TX** LEDs shining through\nthe white PLA — here the blink firmware has the **TX** LED on. This is\nsomething of a happy accident: if you don't want the glow, print the\ncase in black or another dark material, or simply leave the RX/TX LEDs\nunpopulated.\n\n\u003e **Note:** The USB-C cut-out in the current print is slightly too wide.\n\u003e It's a cosmetic issue only — the port works fine — and will be tidied\n\u003e up shortly so the opening sits more symmetrically around the connector.\n\n## Files (amiga/)\n\n- `par2ser.c` — device skeleton + serial command set + receive ring buffer\n- `transport.h` / `transport.c` — byte-pipe to the adapter (**stubbed** for now)\n- `debug.c` — `KPrintF` over `RawDoFmt`/`RawPutChar` (verbatim from SimpleDevice)\n- `Makefile`\n\n## Build (amiga/)\n\n```sh\ncd amiga\nmake debug      # build-debug/par2ser.device, with KPrintF tracing\nmake release    # build-release/par2ser.device, stripped\n```\n\nAdjust `INCDIRS` for your NDK path as in SimpleDevice.\n\n## Programming the FT240X (one-time, before first use)\n\nThe CPLD needs a 12 MHz clock from the FT240X to operate. By default\nthe FT240X's CBUS5 pin is **not** configured as a clock output — you\nhave to set its function in the chip's internal MTP (one-time-programmable)\nmemory using FTDI's **FT_PROG** utility. While you're at it, you should\nalso tell the chip to advertise itself as a Virtual COM Port (VCP) so\nthat comms software on the host can open it as a regular serial port,\nand you can optionally set a friendly USB product-description string.\n\nThese settings are all stored on the FT240X chip itself — they\npersist across power cycles and across host machines.\n\n### What you'll need\n\n- FTDI **FT_PROG** (free download from \u003chttps://ftdichip.com/utilities/\u003e;\n  requires .NET Framework 4.0 or newer, which is included with\n  Windows 8.1 and above)\n- The Rev 2A board, powered via USB, on a Windows machine (FT_PROG\n  is Windows-only; users on Linux/macOS can use a Windows VM, or\n  the open-source `ftdi_eeprom` from libftdi as an alternative —\n  see note at the end of this section)\n\n### Install FT_PROG\n\nDownload FT_PROG from \u003chttps://ftdichip.com/utilities/\u003e (current version\nat time of writing: 3.12.75.692). Extract the ZIP, run the installer,\nclick through to **Finish**:\n\n![FT_PROG installer](images/FT_PROG_installation.png)\n\n### Fast path: apply the supplied template\n\nThe `FT_PROG/Par2Ser.xml` file in this repo is a saved FT_PROG template\nwith all the settings the Par2Ser bridge needs (VCP enabled, CBUS5 →\nCLK12MHz, CBUS6 → Keep_Awake#, Product Description → `Par2Ser USB Serial`).\nThe fast path is:\n\n1. Plug the Rev 2A board into a Windows PC via USB-C. Windows will\n   detect the FT240X and bind FTDI's bus-level driver, presenting\n   the device as **\"USB Serial Converter\"** under\n   *Universal Serial Bus controllers* in Device Manager.\n2. Launch FT_PROG and **FILE → Open** the `FT_PROG/Par2Ser.xml`\n   template — this loads the desired settings into FT_PROG's editor.\n3. **DEVICES → Scan and Parse** (\u003ckbd\u003eCtrl+P\u003c/kbd\u003e) to bring the\n   live chip's current settings under the same editor.\n4. **DEVICES → Program** to apply the template values to the chip\n   — confirm the success dialog appears.\n5. Unplug and replug the board.\n\nIf you'd rather understand or customize each setting, walk through\nthe manual steps below instead.\n\n### Manual walkthrough (step-by-step)\n\n1. Plug the Rev 2A board into a Windows PC via USB-C. Windows will\n   detect the FT240X and bind FTDI's bus-level driver, presenting\n   the device as **\"USB Serial Converter\"** under\n   *Universal Serial Bus controllers* in Device Manager. (Whether\n   a COM port appears at this stage depends on the host's driver\n   state — see \"Driver behavior across operating systems\" below.)\n\n2. Launch FT_PROG. Click **DEVICES → Scan and Parse** (or\n   \u003ckbd\u003eCtrl+P\u003c/kbd\u003e). The device tree on the left should populate\n   with the FT240X, and the lower pane shows the EEPROM contents\n   dump:\n\n   ![FT_PROG after Scan and Parse](images/FT_PROG_config_pic1.png)\n\n3. Enable the **VCP driver mode**: in the device tree, expand\n   **Hardware Specific → Port A → Driver** and select the\n   **Virtual COM Port** radio button (it may be on \"D2XX Direct\"\n   by default):\n\n   ![Virtual COM Port radio button selected](images/FT_PROG_config_pic2.png)\n\n4. Configure the **CBUS5 clock output**: navigate to\n   **Hardware Specific → CBUS Signals** and set the **C5** drop-down\n   to **`CLK12MHz`**. The C6 drop-down can be left at its default\n   (`Keep_Awake#`) — CBUS6 is wired to the CPLD but not used by the\n   current firmware:\n\n   ![C5 set to CLK12MHz](images/FT_PROG_config_pic3.png)\n\n5. (Optional) Update the **USB String Descriptors** to identify the\n   device as a Par2Ser. Setting the *Product Description* to\n   `Par2Ser USB Serial` makes it easier to find when several FTDI\n   devices are plugged into the same host. The factory-assigned\n   *Serial Number* is unique per chip and stable — useful when\n   binding driver settings or `udev` rules per device:\n\n   ![Product Description set to Par2Ser USB Serial](images/FT_PROG_config_pic4.png)\n\n6. Click **DEVICES → Program** (the lightning-bolt icon). The\n   *Program Devices* dialog shows the chip type, VID/PID, and the\n   strings about to be written to MTP. Confirm the values look right\n   and click **Program**:\n\n   ![Program Devices dialog](images/FT_PROG_config_pic5.png)\n\n   You should see **\"Programming Successful\"** at the bottom of the\n   dialog when the write completes:\n\n   ![Programming Successful](images/FT_PROG_config_pic6.png)\n\n7. Unplug and replug the board. Windows will re-enumerate the device.\n\n### Verifying the configuration\n\nAfter the FT_PROG round-trip, you can confirm the chip is configured\ncorrectly with one or both of:\n\n**A. Oscilloscope check of the 12 MHz clock.** With the board powered\nvia USB, probe the trace at R5 (the damping resistor on the CPLD's\nclock input). You should see a clean ~12 MHz square wave near rail-to-rail\non a 3.3 V LVTTL swing:\n\n![12 MHz clock at R5](images/FT240XS_12MHz_clock.png)\n\nThe small overshoot/ringing on the edges is the scope probe's ground-lead\ninductance, not a problem with the signal — using a probe ground spring\nclose to the test point cleans it up. The signal is well within LVTTL\ninput tolerances at the CPLD's pin 43.\n\n**B. COM-port enumeration check on the host.** The board should appear\nas a serial port. The device name varies by OS — see below.\n\n### Driver behavior across operating systems\n\nThe FT_PROG settings live on the chip; *whether* a given host then\nmakes them visible as a normal COM/tty port depends on what FTDI driver\nsupport that host has. Tested behavior so far:\n\n| Host                    | Result                                  | Driver intervention needed |\n|-------------------------|-----------------------------------------|----------------------------|\n| **macOS 10.15 Catalina** | `/dev/cu.usbserial-XXXXXXXX` on plug-in | None — Apple's built-in `AppleUSBFTDI` driver handles it |\n| **Linux** (Pop!\\_OS, Ubuntu, similar) | `/dev/ttyUSB0` on plug-in     | None — the in-kernel `ftdi_sio` module binds automatically |\n| **Windows 10/11**       | `USB Serial Port (COMn)` under *Ports (COM \u0026 LPT)* | Typically none — Windows Update pushes the FTDI CDM (Combined Driver Model) package automatically |\n| **Windows 8.1**         | Depends on the machine's history (see below) | One-time CDM install on a fresh host |\n\nThe Windows 8.1 case is the only one with a footgun, and it's\nmachine-specific rather than OS-specific. On Windows 8.1, the **CDM\n(Combined Driver Model)** package — which contains both the bus-level\ndriver (`USB Serial Converter`) *and* the VCP layer that creates the\nCOM port — is not bundled with the OS. It can be installed via\nWindows Update, but isn't always pushed automatically.\n\nIn our testing on two Windows 8.1 SP2 machines:\n\n- **Machine A**: had previously hosted other FTDI devices. When the\n  Par2Ser board was first plugged in, Windows auto-installed both\n  the USB Serial Converter and the VCP layer, and a COM port\n  (`COM4`) appeared under *Ports (COM \u0026 LPT)* immediately. The\n  \"Installing Par2Ser USB Serial\" progress dialog appeared\n  automatically:\n\n  ![Windows automatic install dialog](images/Windows_plug_and_play_pic1.png)\n\n  After the install, Device Manager's Events tab on the resulting\n  `USB Serial Port (COMn)` entry shows the FTDI VCP driver service\n  `FTSER2K` being registered and `ftdiport.inf` driving the COM-port\n  instance — the proof that the VCP layer attached on top of the\n  bus-level driver:\n\n  ![COM port Events tab showing FTSER2K registration](images/Windows_plug_and_play_pic2.png)\n\n- **Machine B**: had not previously had an FTDI device on it.\n  Plugging in the Par2Ser board only created the *USB Serial\n  Converter* entry under *Universal Serial Bus controllers*; no COM\n  port appeared. **The fix on this machine turned out to be very\n  simple**: right-click *USB Serial Converter* in Device Manager,\n  choose **Uninstall**, in the dialog that appears **leave the\n  \"Delete the driver software for this device\" checkbox unchecked**,\n  click OK, then unplug and replug the board. Windows re-enumerated\n  the device, picked up the VCP driver this time, and `COM10`\n  appeared under *Ports (COM \u0026 LPT)*. Total time: about 30 seconds.\n\n  This \"uninstall (keep files) then replug\" trick works on a Win8.1\n  machine that has the FTDI VCP driver files present on disk but\n  somehow bound only the bus-level driver on the first plug-in.\n  The driver files are kept; only the device-to-driver binding is\n  cleared, so the next enumeration can re-pick the correct (full)\n  driver stack.\n\n**If you're on Windows 8.1 (or earlier) and no COM port appears**,\ntry the uninstall-without-deleting-files trick first — it's quick\nand reversible. If that doesn't work (the VCP driver files truly\naren't present on the machine), install FTDI's CDM driver package\nfrom \u003chttps://ftdichip.com/drivers/vcp-drivers/\u003e — download the\n*setup executable*, unplug the board, run the installer, replug.\nAfter that the COM port will appear on every subsequent plug-in.\nThe MTP setting in the chip stays correct throughout; only the\nhost needs the right driver layer bound.\n\nOn Linux and macOS, no equivalent step is needed — the driver shipped\nwith the OS supports the FT240X out of the box.\n\n### Linux/macOS alternative for the MTP programming (libftdi)\n\nOn non-Windows systems, the MTP programming (CBUS5 → CLK12MHz, VCP\nenable, etc.) can be done with `ftdi_eeprom` from the `libftdi`\npackage — but it has not been tested by the author of this repo.\nYou'd need a small config file pointing at the FT240X (matched by\nVID/PID `0403:6015`) and setting `cbus5=CLK12`. See the libftdi\ndocumentation for the exact syntax.\n\nThe simplest path for now is to do the one-time FT_PROG step on any\navailable Windows machine. Once the FT240X's MTP is programmed, the\nchip behaves identically on any host.\n\n## Programming the CPLD via JTAG\n\nThe LC4064V is programmed in-circuit via the 2x5 JTAG header (J3)\nusing **ispVM System** (the legacy Lattice programming tool, bundled\nwith the free ispLEVER Classic install). For the JTAG cable, an\ninexpensive **FT4232H Mini Module** works well as a generic FTDI\ncable that ispVM recognizes as `USB2 / FTUSB-0` without needing any\nEEPROM modification.\n\n### Wiring (FT4232H Mini Module ↔ Par2Ser J3)\n\nThe FT4232H's channel A MPSSE pins map to JTAG signals as follows:\n\n| FT4232H Mini Module | JTAG signal | Par2Ser J3 pin |\n|---------------------|-------------|----------------|\n| **AD0** (ADBUS0)    | TCK         | pin 1 (TCK)    |\n| **AD1** (ADBUS1)    | TDI         | pin 5 (TDI)    |\n| **AD2** (ADBUS2)    | TDO         | pin 7 (TDO)    |\n| **AD3** (ADBUS3)    | TMS         | pin 3 (TMS)    |\n| any GND on module   | GND         | pin 2 or 4     |\n\nDo NOT connect the FT4232H's 3.3 V or 5 V output to J3 — the\nPar2Ser self-powers from USB-C and J3 pin 6 (3V3) is an output\nfrom the board, not a power input.\n\nThe J3 header doesn't have to be soldered down — you can press\nthe 2x5 ribbon connector (or individual jumper wires) against the\nthrough-hole pads with gentle hand-held force during programming.\n\n*Note: RN2, the 10 kΩ pull-up network for TMS, can be left\nunpopulated and JTAG will still work. The FT4232H actively drives\nTMS during programming, and the LC4064V has a weak internal\npull-up on TMS per IEEE 1149.1. RN2 should still be populated\nbefore final use for noise immunity when the JTAG cable is\ndisconnected.*\n\n![Par2Ser JTAG programming with FT4232H Mini Module](images/Par2Ser_JTAG_programming_with_FT4232H-56Q.jpg)\n\n### Driver setup (Windows)\n\nFor ispVM to talk to the JTAG cable, **channel A (Interface 0) of\nthe FT4232H must be bound to FTDI's D2XX driver** (not\nlibusb-win32, WinUSB, or libusbK). The other three interfaces\n(B/C/D) are not used by ispVM and can stay bound to whatever\ndriver they had previously.\n\nAfter plugging in the Mini Module, open Device Manager and locate\nthe four \"Quad RS232-HS\" entries (Interface 0/1/2/3). If\nInterface 0 is bound to the wrong driver — for example, listed\nunder *libusb-win32 device* (a typical leftover from a previous\nOpenOCD session) rather than under *Universal Serial Bus\ncontrollers* — rebind it:\n\n1. Right-click **Quad RS232-HS (Interface 0)** → **Update Driver\n   Software** → **Browse my computer for driver software** →\n   **Let me pick from a list of devices on my computer**.\n2. Select **USB Serial Converter A** (FTDI's D2XX driver, version\n   2.12.36.4 or newer).\n3. Click Next. Windows will rebind Interface 0 to the D2XX driver\n   without affecting Interfaces 1–3.\n4. **Restart ispLEVER/ispVM** — without this, the running ispVM\n   process still has the old driver state cached and will not see\n   the cable.\n\nAfter the rebind, Device Manager should show one entry as\n`USB Serial Converter A` under *Universal Serial Bus controllers*\n(Interface 0, the one ispVM will use), and the other three\ninterfaces (1/2/3) wherever they were before — that's fine, they're\nnot used for JTAG.\n\n### Programming procedure\n\n1. **Power the Par2Ser from a USB charger**, not from the same PC\n   running ispVM. This is important: if the Par2Ser is plugged into\n   the same Windows host that is running ispVM, both FTDI devices\n   (the Par2Ser's FT240X and the FT4232H Mini Module) appear as\n   \"USB Serial Converter\" entries, and ispVM can grab the wrong one.\n   Powering Par2Ser from a separate USB charger keeps it powered\n   while leaving only the FT4232H Mini Module visible to ispVM.\n\n2. **Connect the JTAG cable** per the wiring table above, with the\n   FT4232H Mini Module plugged into the Windows PC.\n\n3. **Launch ispVM System** (Start Menu → Lattice Semiconductor →\n   ispVM System).\n\n4. **Scan Board** (toolbar button) — should detect the LC4064V and\n   show it as `LC4064V(B)-32IO` in the chain. (The `(B)-32IO` is\n   ispVM's internal name for the 64-macrocell, 32-IO variant — your\n   physical chip is the TQFP48 package of that die.)\n\n5. **Double-click the device row** in the chain → set **Data File**\n   to the `.jed` file generated by the ispLEVER fitter → set\n   **Operation** to *Erase, Program, Verify*.\n\n6. **(Important) Slow down TCK for flywire JTAG.** Open\n   **Project → Project Settings → Advanced** and set\n   **TCK Low Pulse Width Delay** to **3** or higher. The default\n   15 MHz TCK is too fast for the typical flywire connection from\n   the FT4232H to J3 — the verify step will fail with all-zeros\n   readback on TDO. Stretching the TCK low-pulse by 3× makes\n   programming reliable. Note that this setting is **per-project\n   in ispVM**, so it has to be set again when switching projects.\n\n7. **Click GO** (green arrow). Programming should complete in 3–10\n   seconds with \"Operation: Successful\" and a green PASS in the\n   Status column.\n\n![ispVM JTAG programming setup with TCK Low Pulse Width Delay = 3](images/ispVM_JTAG_programming_setup.png)\n\nIf the TCK Low Pulse Width Delay setting is left at the default\n(1) and Debug mode is off, you'll see a `Failed in Function\nVERIFY_USERCODE` error in the log, with received TDO reading all\nzeros where the expected pattern was the programmed bitstream.\nThat's the signature of marginal TCK timing on flywire JTAG;\nincreasing the TCK Low Pulse Width Delay is the fix. (Enabling\nDebug mode also happens to make programming work — the per-\ntransaction logging on the PC side adds enough pacing between\nJTAG operations to mask the signal-integrity issue — but that's\nan incidental workaround. The proper fix is the TCK delay\nsetting.)\n\n## Milestone 1 — does kermit accept it? (no hardware needed) ✅\n\nThis milestone is **done**. It validates the driver in WinUAE without\nany hardware:\n\n1. `make debug` in `amiga/`, copy `build-debug/par2ser.device` to `DEVS:`\n   in WinUAE.\n2. Open a serial debug console (the same `RawPutChar` path SimpleDevice\n   uses).\n3. In kermit: `set line par2ser.device`. The trace shows `do_open()`,\n   then the commands kermit issues (`SDCMD_SETPARAMS`, `SDCMD_QUERY`, …)\n   with their parameters and the status word we return.\n\nIn this milestone `transport_write()` discards bytes (reports them sent)\nand no RX data ever arrives, so a `CMD_READ` will stay pending — expected\nwith no hardware. The goal is purely to confirm acceptance and observe\nthe negotiation, especially the carrier check.\n\n## Carrier / `/CD` handling\n\nkermit checks carrier-detect before it will use the line. We have no real\nCIA serial lines on the parallel port, so `SDCMD_QUERY` **synthesizes**\nthe status word. `serial.device` returns the raw (active-low) CIA-B\ncontrol lines, i.e. `0` = signal asserted, so the default\n`ST_CARRIER_PRESENT = 0` reports CD/CTS/DSR all asserted.\n\nThe full word is `KPrintF`'d in `sdcmd_Query`, so if kermit reports\n**NO CARRIER**, flip the polarity in `par2ser.c`:\n```c\n#define ST_CARRIER_PRESENT  ST_CD   /* try this if 0 doesn't satisfy kermit */\n```\nand compare the logged status against what kermit expects.\n\n## Milestone 2 — real adapter ✅ (interactive traffic both ways)\n\n### Transmit — working on hardware ✅\n\nThe Amiga → PC direction is verified on a real Rev 2A board: typing in\nc-kermit (`cki196`) after `set line par2ser.device` / `connect` produces the\ncharacters in a PC terminal on the FT240X's USB serial port, with the driver's\n`KPrintF` trace confirming each `CMD_WRITE`.\n\nBring-up steps:\n\n1. Build the CPLD firmware in ispLEVER Classic 2.1 — see `cpld/README.md`\n   for details. The result is a `par2ser.jed` file.\n2. Program the FT240X's CBUS5 to CLK12MHz output (see above).\n3. Program the CPLD via ispVM System using a JTAG cable.\n4. Build the driver with `make debug` in `amiga/` (the `Makefile` has\n   `-DPAR2SER_HW` and the adapter objects enabled), copy\n   `build-debug/par2ser.device` to `DEVS:`.\n\nThe low-level transport lives in `amiga/low-lib/` (`adapter.c`, `adapter.h`,\n`adapter_low.s`). It is derived from Niklas Ekström's parallel-adapter\ntransport but renamed and reworked for Par2Ser: it is a byte-pipe, not SPI,\nso the chip-select / card-present / speed-switch machinery was removed, the\nfast-path assembly was ported from vasm to GNU-as syntax for the\n`m68k-amiga-elf` toolchain, and the SD-card init was replaced with a plain\nparallel-port grab. The WRITE1/READ1 command encoding and the SELECT/POUT/BUSY\nhandshake are unchanged and are decoded bit-for-bit by the CPLD FSM.\n\nOne hardware bug surfaced during TX bring-up and is fixed in the current RTL:\nthe FT240X write strobe was firing one clock before the CPLD drove the data\nbus, so the chip latched a floating bus and bytes arrived as garbage. Driving\nthe data across the WR pulse (setup + hold around the falling edge) fixed it;\nsee `cpld/rtl/par2ser_fsm.v`.\n\n### Receive — working on hardware ✅\n\nThe PC → Amiga direction also works: characters typed in a PC terminal appear\nin c-kermit on the Amiga (`PAR2SER_RX_ENABLED` is 1 in `transport.h`).\n\nRX design: the adapter's ACK line (open-drain, DB25 pin 10) connects only to\n**CIA-A /FLAG**, an interrupt-only CIA input — confirmed against the KiCad\nnetlist — so there is no readable doorbell level; the FLAG interrupt itself is\nthe data-available signal. The driver registers on the FLAG ICR bit via\n**cia.resource** (`AddICRVector`, see `amiga/low-lib/cia_protos.h`) rather\nthan an `INTB_PORTS` server, so only genuine FLAG events are dispatched and\nthe shared ICR is owned correctly. The handler reads exactly **one byte per\nFLAG**: the CPLD's IDLE-gated ACK re-asserts after each READ1 completes if\nthe FIFO still holds data, producing a fresh /FLAG edge per remaining byte —\nthe drain is hardware-self-clocking, no loop in the interrupt. A one-shot\n`transport_rx_prime()` at device-open regenerates the doorbell edge for any\ndata that arrived before the interrupt was enabled (the CIA latches edges,\nnot levels).\n\nGetting RX to work surfaced and fixed several deep bugs, documented in the\ncommit history — most notably a **gcc calling-convention trap**: `asm(\"reg\")`\nparameter annotations are honored on function *definitions* but silently\nignored on *prototypes*, so cross-file calls into the adapter transfer\nfunctions passed garbage in a0/d0 (every READ1 scribbled memory through a\njunk pointer; TX had only appeared correct by register coincidence). The\nadapter API now uses the plain C convention, with explicit register variables\n+ inline `jsr` shims only at the true `adapter_low.s` asm boundary. On the\nCPLD side, the READ handshake was reworked: never drive the Amiga bus before\nits first POUT edge (eliminating microseconds of bus contention against the\nCIA on every read), present one byte per edge and hold it across the CIA's\n~1.4 µs read, and capture FT240X data while RD# is still low. 58/64\nmacrocells, timing met with 72 ns slack.\n\n### Known issues / next 🚧\n\n- **Kermit file transfers fail** (`send`/`rdir` → \"?Too many retries\"):\n  interactive byte traffic is solid both ways, but protocol packet bursts\n  get corrupted or clipped — packets flow (all-Error packet exchanges are\n  observed) but never complete. Prime suspects: RX overrun during\n  per-byte-interrupt bursts, or larger CMD_READ/CMD_WRITE patterns that\n  single keystrokes never exercised. This is the current debugging target.\n- **TX LED never visibly lights**: `led_tx` follows `drive_ft_d`, which is\n  high ~166 ns per byte — too short to see. The RX and activity LEDs blink\n  only briefly for the same reason. A pulse-stretcher counter in the CPLD\n  (~50 ms per event) would fix all three; there is macrocell headroom now.\n- Non-ASCII characters (å/ä/ö) may display wrong on the PC — check the\n  Windows console codepage (the link itself is 8-bit clean).\n\n## Credits\n\n- **Niklas Ekström** — the 2E par-to-spi protocol and the SDBox\n  adapter that this project is derived from. See his\n  [amiga-par-to-spi-adapter](https://github.com/niklasekstrom/amiga-par-to-spi-adapter).\n- **Iain Barclay** — `8n1.device` 43.5, the serial machinery template.\n- **Bartman** — the `m68k-amiga-elf` toolchain.\n\n## License\n\nLicensed under [Creative Commons Attribution-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-sa/4.0/)\n(CC-BY-SA 4.0). You're free to use, modify, and redistribute this work\n(including commercially), provided you give appropriate credit and\ndistribute derivative works under the same license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbilander%2Fpar2ser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjbilander%2Fpar2ser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbilander%2Fpar2ser/lists"}