{"id":22123092,"url":"https://github.com/bcrist/re4k","last_synced_at":"2025-07-25T14:31:30.154Z","repository":{"id":63647318,"uuid":"567984677","full_name":"bcrist/re4k","owner":"bcrist","description":null,"archived":false,"fork":false,"pushed_at":"2024-04-27T00:47:37.000Z","size":7526,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-27T01:38:36.646Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bcrist.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}},"created_at":"2022-11-19T04:33:08.000Z","updated_at":"2024-04-27T01:38:38.752Z","dependencies_parsed_at":"2023-02-19T04:16:12.825Z","dependency_job_id":null,"html_url":"https://github.com/bcrist/re4k","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcrist%2Fre4k","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcrist%2Fre4k/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcrist%2Fre4k/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcrist%2Fre4k/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bcrist","download_url":"https://codeload.github.com/bcrist/re4k/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227585102,"owners_count":17789807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2024-12-01T15:29:21.062Z","updated_at":"2025-07-25T14:31:30.137Z","avatar_url":"https://github.com/bcrist.png","language":"Zig","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fusemaps for Lattice ispMach4000 CPLDs\n\nThis repo contains reverse-engineered fusemaps for most of the commonly available LC4k CPLDs from Lattice.\n\nData is provided in text files containing machine and human readable S-Expressions describing the fuse locations that control each feature.\nThese are intended to be used to generate libraries so that CPLD configurations can be created using whatever programming language is desired.\nExisting libraries include:\n\n* [Zig-LC4k](https://github.com/bcrist/Zig-LC4k)\n\nIf you build a library/bindings for another language, let me know so I can list it here!\n\n## Device List\n\n|            |TQFP44|TQFP48|TQFP100|TQFP128|TQFP144|csBGA56|csBGA64|csBGA132|csBGA144|ucBGA64|ucBGA132|\n|:-----------|:----:|:----:|:-----:|:-----:|:-----:|:-----:|:-----:|:------:|:------:|:-----:|:------:|\n|LC4032V/B/C | ✔️    | ✔️    |       |       |       |       |       |        |        |       |        |\n|LC4032ZC    |      | ✔️    |       |       |       | ✔️     |       |        |        |       |        |\n|LC4032ZE    |      | ✔️    |       |       |       |       | ✔️     |        |        |       |        |\n|LC4064V/B/C | ✔️    | ✔️    | ✔️     |       |       |       |       |        |        |       |        |\n|LC4064ZC    |      | ✔️    | ✔️     |       |       | ✔️     |       | ✔️      |        |       |        |\n|LC4064ZE    |      | ✔️    | ✔️     |       |       |       | ✔️     |        | ✔️      | ✔️     |        |\n|LC4128V     |      |      | ✔️     | ✔️     | ✔️     |       |       |        |        |       |        |\n|LC4128B/C   |      |      | ✔️     | ✔️     |       |       |       |        |        |       |        |\n|LC4128ZC    |      |      | ✔️     |       |       |       |       | ✔️      |        |       |        |\n|LC4128ZE    |      |      | ✔️     |       | ✔️     |       |       |        | ✔️      |       | ✔️      |\n\nLC4256 and larger devices are not supported at this time.\nAutomotive (LA4xxx) variants likely use the same fusemaps as their LC counterparts, but that's just conjecture.\nPlease don't use this project for any automotive or other safety-critical application.\n\n## Introduction\nPlease read through the Lattice datasheet for your device if you have not.\nGenerally I have tried to use the same terminology for things as is used there.\nYou can also reference the glossary at the end of this document if you are unsure of what an acronym or term means.\nYou can find PDF and KiCAD format schematics showing the structure of each type of device in the `schematics` directory.\n\n## General Fusemap Layout\nAll LC4k devices have a logical layout of fuses into a 2D grid with either 100 or 95 rows,\nand a variable number of columns, depending on the number of GLBs in the device.\nThe JEDEC files list these fuses one row after another,\nand when programming the device via JTAG each row is delivered in a separate SDR transaction.\n\nEach GLB uses a chunk of at least 86 columns,\nand the GLBs are laid out side-by-side,\nhowever they are not generally ordered from left to right\n(the block for GLB \"A\" is not necessarily to the left of the block for GLB \"B\").\n\nThe first 72 rows contain PT and GI routing fuses.\nThis part of the fusemap is densely packed;\nevery single logical fuse corresponds to a bit of FLASH memory and controls the behavior of the device.\n\nThe remaining rows have a variety of uses, and are sparsely packed;\nmost bits don't actually correspond to FLASH memory cells, and always read as a `1`, even after attempting to program them to `0`.\n\nGenerally there is a single column corresponding to each macrocell slice, containing fuses that configure that macrocell slice.\nThese columns are arranged in groups of two, usually with 8 mostly-unused columns separating each pair.\nDevices that only have 95 rows only have a single I/O cell per pair of macrocells.\nInstead of placing all the I/O cell configuration fuses in the same column,\nhalf of the fuses are shifted over to the adjacent macrocell's column,\nreducing the total number of rows needed.\n\nEach GLB has a few bits of block configuration which are placed in the \"borders\" to the left and right of the macrocell slice columns.\nThis includes fuses for configuring block clock source/polarity, shared PT polarity, routing of the shared PT enable to the GOE bus, etc.\n\nFinally, global configuration is typically placed in a small, vaguely ring-shaped structure at the right edge of one of the GLB regions.\nThis includes configuration of input-only pins, GOE polarity, and oscillator/timer (in ZE devices).\n\n## S-Expression Files\nThe reverse-engineered fusemap for each device consists of a set of s-expression files in `LC4xxx/LC4xxx*_*/.sx`.\nThere is also a combined file `LC4xxx/LC4xxx*_*.sx` which contains the data from all of the individual files.\nThe meaning of the data in each particular file is explained below.\nIf the syntax of any of the files is confusing to you after reading its corresponding section,\nplease open an issue so I can try to document it better.\n\n### `grp.sx` `(global_routing_pool)`\nEach GLB has 36 GI \"slots\" which (along with their complements) are used as inputs to the product terms in that GLB.\nEach GI can be selected from a fixed set of signals in the global routing pool.\nThe options are different for each GI \"slot\" in the GLB,\nbut every GLB in the device uses the same options for the same GI slot.\nThe number of options for each slot depends on the device type\n(devices with more GLBs have more GRP signals,\ntherefore in order to have multiple possible routings for each signal,\neach GLB must have more possible options).\n\nFor devices that have an even number of GI options,\nthe option fuses are stored at the very left side of the GLB block,\nusing `N/2` columns (where `N` is the number of options).\nA \"one-cold\" encoding is used here; i.e. there is one fuse for each option,\nand only one fuse should be programmed to 0 for each GI.\n\nFor devices that have an odd number of GI options, the GLBs are organized into pairs,\nand each pair shares the same columns of GI routing fuses.  The first row contains fuses\nfor one of the GLBs, and the second row contains fuses for the other.\n\n### `pterms.sx` `(product_terms)`\nWithin the first 72 rows, each column\n(with the exception of the columns used for GI routing above)\nrepresents a single product term.\nEvery pair of rows corresponds to a single GI slot,\nwith the first row representing the non-inverted GI signal,\nand the second row representing the inverted version of the same signal.\n\nProgramming a fuse within a product term to 0 means the corresponding signal must be asserted\nin order for the product term to output `true`.\nAnother way to think of this is that the fuse value is OR-ed with the signal, and the result is\npassed into the product term's AND gate.\nTherefore if no PT fuses are set to 0, the PT will always yield `true`.\nIf both fuses are set to 0 for any GI, the PT will always yield `false`.\nWhen the lpf4k fitter wants to make a PT `false`,\nit sets all the fuses for the first dozen or so rowss to 0.\nIt's not clear why they chose to set just those.\nIt may be that setting just one pair to 0 might create static hazards\nif the GI mapped to that slot changes.\nBut in that case wouldn't it be best to set all GI pairs to zeroes?\nIn testing, that does seem to work as expected,\nso that's what I'd recommend doing.\nMy best guess is that this could be a holdover from older device families\nthat used sense amplifiers instead of fully CMOS logic.\nSetting all fuses to 0 might cause higher power usage in such devices.\n\nProduct terms are grouped into clusters of 5,\nwith one cluster associated with each macrocell.\nAdditionally, there are 3 extra product terms per GLB,\nwhich may be used for specific purposes,\nbut are shared amongst all macrocells in the GLB.\nThese PTs are always in the last 3 columns of the GLB's block.\n\n### `cluster_routing.sx` `(cluster_routing)`\nEach product term can optionally be used for a special purpose related to that macrocell (see below),\nor they can be summed (OR-ed) together and fed into the macrocell's logic input.\n\nSince a logic equation simplified to a sum-of-products often requires more than 5 product terms,\na cluster can either keep it's sum for itself,\nor it can \"donate\" it to one of up to three nearby macrocells.\nEach cluster then creates a second sum from any intermediate sums that were routed to that cluster.\nA cluster can receive a \"donation\" (or multiple) even if it is not \"keeping\" it's own original sum.\nTherefore this second sum can represent up to 20 product terms, all with a constant propagation delay.\nSome specific clusters have a maximum of \u003c 20 PTs:\n\n* The cluster for MC 0 can only receive a sum from cluster 1 or cluster 2, so including itself it has a maximum of 15 PTs.\n* The cluster for MC 14 can only receive a sum from cluster 13 or cluster 15, so including itself it has a maximum of 15 PTs.\n* The cluster for MC 15 can only receive a sum from cluster 14, so including itself it has a maximum of 10 PTs.\n\nA cluster sum can only be routed to one other cluster;\nit can't be duplicated and sent to multiple neighboring clusters.\n\n### `wide_routing.sx` `(wide_routing)`\nIn cases where a very large number of product terms are needed,\nbut very few outputs are needed,\nthe output of the second sum above can be redirected to the cluster at index `(N+4)%16`\n(where `N` is the current cluster index).\nThis is referred to in the datasheets as \"SuperWIDE(tm)\" steering logic.\n\nNote that this differs from `cluster_routing` in several ways:\n\n* It \"wraps around\", so cluster 15 can be routed to cluster 3.\n* It can be \"chained\" such that any macrocell in the GLB can potentially use every PT cluster, if no other MCs in the GLB need a cluster.\n* Using this feature increases the maximum propagation delay (but not equally; PTs that go through the wide routing will be slower than those in the final cluster's 20-PT group).\n\nWhen a macrocell's cluster is routed away to another cluster,\nthe macrocell sees a constant low (false) value as its logic input.\n\n### `input_bypass.sx` `(macrocell_data)`\nA macrocell register's data/toggle input may be configured to come directly from the macrocell's input pad,\ninstead of having to travel through the GRP, PTs, cluster routing, etc.\nThis provides a reduced minimum setup time.\n\nTechnically this feature can also be used when the macrocell is configured for combinational logic,\nbut there's not much point in doing so,\nsince that just makes the macrocell feedback signal the same as the input buffer signal.\nYou could use an ORM offset to create a tri-state line driver where the input and output are both pins,\nand the OE signal is controlled by the CPLD logic.\nThis would yield the fastest possible propagation delay across the line driver,\nbut if propagation delay is that critical,\nyou'd probably be better off just outputting the OE signal and using an external tri-state buffer or bus switch.\n\n### `zerohold.sx` `(zero_hold_time)`\nWhen a macrocell is configured as an input register,\nan extra delay can be added to bring the minimum hold time down to 0.\nThis also means the setup time is increased.\nThis is controlled by a single fuse that affects the entire chip.\nRegisters whose data comes from product term logic are not affected by this fuse,\nbecause the internal propagation delays mean that no hold time is required anyway.\n\n### `pt0_xor.sx` `(pt0_xor)`\nEach macrocell contains an XOR gate.\nThe output of the XOR gate goes to the data/toggle input of the macrocell's register,\nand optionally to the macrocell feedback/ORM input (when the MC is in combinational mode).\n\nOne of the inputs to the XOR gate is always the logic input from the PT cluster router.\n\nThe second input of the XOR gate can be either a constant value,\nor the result of the macrocell's first product term, PT0.\nWhen it is sourced from PT0, that product term is removed from its cluster sum.\nWhen PT0 is not redirected, a logic 0 is fed to the XOR (optionally inverted; see below).\n\nNote that the datasheets' macrocell schematic (fig. 5)\ndepicts the input register mux feeding into one of the XOR inputs,\nhowever when testing real devices,\nwe see that the XOR gate is bypassed completely when the `input_register` fuse is cleared.\nThis implies that the input register mux is actually located after the XOR output.\nThis makes sense, since the idea of the input register is to make the setup time as short as possible.\n\n### `invert.sx` `(invert)`\nThe second input of the XOR gate can be inverted using this fuse.\nWhen sourced from PT0, this means PT0 can be thought as a 36-input OR gate\ninstead of a 36-input AND gate (via a De Morgan transformation;\nyou must also use the complement of each PT0 input of course).\n\nWhen the inverter is enabled, but the XOR is not sourced from PT0,\nthe second XOR input becomes a constant high,\nso the logic sum from the PT cluster router is inverted.\nAgain, one way to think of this is that you can use the macrocell as a product-of-sums\ninstead of a sum-of-products.\n\n### `mc_func.sx` `(macrocell_function)`\nEach macrocell can implement one of four fundamental circuits:\n\n* Purely combinational logic\n* Transparent latch\n* D flip-flop\n* T flip-flop\n\nThe latter 3 all act as single bit storage elements,\nand thus have some extra configuration that is irrelevant for combinational macrocells:\n\n* Clock source\n* Clock enable source\n* Power-up initialization\n* Asynchronous set/reset\n\nThese features are described below.\n\n### `clock_source.sx` `(clock_source)`\nWhen a macrocell is used as a register,\nit needs a clock signal, which can be one of eight options:\n\n* Four block clock signals (see below)\n* The GLB's shared clock PT\n* The macrocell's PT1\n* The macrocell's PT1, inverted\n* A constant low/false\n\nWhen it is sourced from PT1, that product term is removed from its cluster sum.\n\nWhen the macrocell is configured as a D or T flip flop, the clock triggers on the rising edge.\nIf if the source can be inverted, it effectively flips it to trigger on the falling edge.\n\nWhen configured as a latch, it will be transparent when the clock signal is high,\nand latched when the clock signal is low.\n\n### `bclk_polarity.sx` `(bclk_polarity)`\nThe four BCLK clock selection options come from dedicated input pins\n(usually four, but some devices only have two).\nUsing these avoids the need to use macrocell PTs or the GLB's shared clock PT for the clock.\nThe polarity of these clocks can be configured independently for each GLB.\nIt is configured in fixed pairs,\nwhere each BCLK can be either the non-inverted version of one of the clocks,\nor the inverted version of the _other_ clock.\nSo you can have both clocks non-inverted, both clocks inverted,\nor a complementary pair of either clock.\n\n### `ce_source.sx` `(clock_enable_source)`\nThe clock enable inhibits the updating of the register contents when it is high.\nIt has no effect when the macrocell is configured for combinational logic.\n\nFor transparent latches, it works effectively as if the clock were ANDed with the CE;\nas long as both are high, the latch is in transparent mode;\nif either goes low, it latches the current value.\n\nFor D and T flip flops, this means as long as the CE is low during the triggering edge,\nthere will be no change that cycle.\nThis is not the same as simply ANDing the CE with the clock signal;\nthe CE does not need to remain low for the entire duration that the clock is high.\n\nThere are four possible sources for the CE signal:\n\n* The macrocell's PT2\n* The macrocell's PT2, inverted\n* The GLB's shared clock PT\n* A constant high/true\n\nThe shared clock PT is the same one that's used as an option for the clock,\nand within a GLB, the same PT can be used as a clock for some MCs and a CE for others.\n\nWhen it is sourced from PT2, that product term is removed from its cluster sum.\nNote that PT2 can also be used for an async set/reset signal (see below).\n\n### `shared_pt_clk_polarity.sx` `(shared_pt_clk_polarity)`\nEach GLB's shared clock PT can optionally be inverted.\nThis affects all usages within the GLB, both as a clock and a clock enable.\n\n### `init_state.sx` `(init_state)`\nWhen a macrocell is configured as a register,\nits initial state at power-up can be configured.\nThis configuration can be selected independently for each macrocell.\n\n### `init_source.sx` `(init_source)`\nWhen a macrocell is configured as a register,\nan signal can be used to asynchronously set or reset the register to its power-up state.\nWhile this signal remains high, the macrocell is forced into its power-up state.\n\nThere are only two options for the source of this signal:\n\n* The macrocell's PT3\n* The GLB's shared init PT\n\nThis means that if the GLB's shared init PT is not a constant false,\nany registers in that GLB that _don't_ want to use a reset signal must use PT3 as a constant false instead.\n\nIt PT3 is used as the source, that product term is removed from its cluster sum.\n\n### `shared_pt_init_polarity.sx` `(shared_pt_init_polarity)`\nEach GLB's shared initialization PT can optionally be inverted.\n\n### `async_source.sx` `(async_source)`\nAn optional second asynchronous set/reset signal can be sourced from PT2.\nWhile the signal remains high, the macrocell is forced into the complement of its power-up state.\n\nNote also that PT2 can also be used as a source for the CE signal,\nand while it is possible to simultaneously use it for both,\ngenerally you wouldn't be able to use the same PT logic for both,\nso this generally you'd use it for one or the other.\n\nWhen PT2 is used as an async set/reset, that product term is removed from its cluster sum.\n\n### `pt4_oe.sx` `(pt4_output_enable)`\nWhen this fuse is programmed,\nPT4 is removed from the macrocell's cluster sum,\nand instead routed to the ORM.\nFrom there it can be selected as an output enable signal for this macrocell's output,\nor certain nearby macrocells (see below).\n\nWhen not used, the OE signal presented to the ORM is a constant false.\n\n### `output_routing.sx` `(output_routing)`\nNormally a macrocell slice's I/O cell will output the signal produced by it's corresponding macrocell,\nhowever there is a built-in \"output routing multiplexer\" (ORM)\nthat allows limited redirection to take the output signal\nfrom a macrocell offset of up to +7 instead.\n\nNote that this offset wraps around as well, so the I/O for MC 15 can be selected from MC 0-6 as well.\n\nThe PT4 OE signal (if used) is also routed from the same MC.\n\n### `output_routing_mode.sx` `(output_routing_mode)`\nFor non-ZE family devices, the ORM can be bypassed, which slightly decreases the output delay.\nAdditionally, the entire macrocell logic block can be bypassed if only a combinational logic output is needed,\nwith a maximum of 5 PTs.\nThere are several options available:\n\n* Output the normal signal selected by the ORM\n* Bypass the ORM and always output the feedback signal from this macrocell, regardless of the ORM configuration\n* Output this cluster's 5-PT sum\n* Output this cluster's 5-PT sum, inverted\n\nNone of these options affect the routing of the PT4 OE signal;\nit always goes through the ORM routing.\n\nWhen one of the 5-PT sum options is used,\nthe PT cluster is still routed using the normal cluster routing rules as well,\nunlike when individual PTs are redirected for a special use.\nIt's possible to still use the buried macrocell,\nbut you have to be careful to isolate the original 5-PT cluster sum, e.g.\n\n* Route it to another cluster\n* Route another always true cluster in and use PT0 for a single PT macrocell\n* Use the buried macrocell as an input register\n\n### `oe_source.sx` `(output_enable_source)`\nEach I/O cell's output driver is active when its output enable signal is high.\nThe OE signal can be selected from one of 8 sources:\n\n* One of 4 global output enables\n* The PT4 output enable signal from the ORM\n* The PT4 output enable signal from the ORM, inverted\n* A constant high (output only)\n* A constant low (input only)\n\n### `goes.sx` `(goe_polarity)`\nAll devices have 4 global OE signals.\nThe polarity of these signals can be configured globally,\nand their source depends on the device.\n\nSources for LC4032 devices:\n\n* GOE0: Shared PT OE bus bit 0\n* GOE1: Shared PT OE bus bit 1\n* GOE2: A0 input buffer\n* GOE3: B15 input buffer\n\nSources for other devices:\n\n* GOE0: Selectable; either shared PT OE bus bit 0, or specific input buffer noted in datasheet\n* GOE1: Selectable; either shared PT OE bus bit 1, or specific input buffer noted in datasheet\n* GOE2: Shared PT OE bus bit 2\n* GOE3: Shared PT OE bus bit 3\n\n### `goes.sx` `(shared_pt_oe_bus)`\nThe shared PT OE bus is a set of 2 or 4 (depending on the device type, as above) global signals\nwhere each bit can be connected to any of the GLBs' shared enable PT\n(note this is shared with the power guard feature on ZE devices).\n\nIf multiple GLBs are configured to drive the same PT OE bus line,\nit will behave as if only the first (lowest numbered) GLB were used.\nIt might have been convenient if they had summed the PTs in this case,\nbut alas, for some reason they didn't.\n\nIf no GLBs are configured to drive a PT OE bus line,\nit is pulled high (if the polarity fuse is 1) or low (if the polarity fuse is 0).\nThere's really no reason to utilize this though, since each output cell can be\nconfigured for \"always output\" or \"always high impedance\" without using any GOE signal.\n\n### `drive.sx` `(drive_type)`\nOne fuse per output controls whether the output is open-drain or push-pull.\n\nOpen-drain can also be emulated by outputing a constant low and using OE to enable or disable it,\nbut that places a lot of limitation on how much logic can be done in the macrocell;\nonly a single PT can be routed to the OE signal.\n\n### `slew.sx` `(slew_rate)`\nOne fuse per output controls the slew rate for that driver.\nAccording to the datasheet,\nusing the slow slew rate adds approximately 1ns to the output buffer propagation delay,\nwhich means rise and fall times are likely about twice as long as normal.\n\n### `threshold.sx` `(input_threshold)`\nThe Lattice fitter allows each input signal's voltage standard to be selected from around a half dozen choices, including:\n* 1.8V LVCMOS\n* 2.5V LVCMOS\n* 3.3V LVCMOS\n* 3.3V LVTTL (5V-tolerant)\n* 3.3V PCI (5V-tolerant)\n\nThe datasheets and IBIS models are quite vague about the actual input structure used in the devices,\nbut it turns out this configuration only affects one fuse per input,\nso it seems that this fuse selects either a high or low input transition threshold.\nGenerally speaking, the high threshold is suitable for either 2.5V or 3.3V signals,\nand the low threshold is for 1.8V or 1.5V signals.\n\nAdditionally, the datasheet mentions that inputs are only 5V-tolerant when V\u003csub\u003eCCO\u003c/sub\u003e is 3.3V,\nso the protection diodes probably clamp relative to that rail rather than V\u003csub\u003eCC\u003c/sub\u003e.\n\nThe following are mostly guesses for the actual V\u003csub\u003eth\u003c/sub\u003e based on the published limits in the datasheet,\nand assuming that the threshold is always referenced to V\u003csub\u003eCC\u003c/sub\u003e,\nas opposed to using V\u003csub\u003eCCO\u003c/sub\u003e or an internal fixed voltage reference.\n\n| V\u003csub\u003eth\u003c/sub\u003e | `-V`                      | `-B`                      | `-C`/`-ZC`                  | `-ZE`                    |\n|:---------------|:-------------------------:|:-------------------------:|:---------------------------:|:------------------------:|\n| low            | 0.28\u0026times;V\u003csub\u003eCC\u003c/sub\u003e | 0.36\u0026times;V\u003csub\u003eCC\u003c/sub\u003e | 0.5\u0026times;V\u003csub\u003eCC\u003c/sub\u003e    | 0.5\u0026times;V\u003csub\u003eCC\u003c/sub\u003e |\n| high           | 0.4\u0026times;V\u003csub\u003eCC\u003c/sub\u003e  | 0.5\u0026times;V\u003csub\u003eCC\u003c/sub\u003e  | 0.73\u0026times;V\u003csub\u003eCC\u003c/sub\u003e   | 0.68\u0026times;V\u003csub\u003eCC\u003c/sub\u003e (falling edge)\u003cbr\u003e0.79\u0026times;V\u003csub\u003eCC\u003c/sub\u003e (rising edge) |\n\n### `bus_maintenance.sx` `(bus_maintenance)`\n2 fuses allow selection of one of four input termination options:\n    * pull up\n    * pull down\n    * bus-hold\n    * floating/high-Z\nIn ZE family devices, this can be configured separately for each input pin.\nIn other families, there is only a single set of fuses which apply to the entire device.\n\n### `bus_maintenance.sx` `(bus_maintenance_extra)`\nOn certain non-ZE devices,\nsetting bus maintenance to floating causes the fitter to toggle additional fuses\nbeyond the two global bus maintenance fuses.\nThis only happens on devices where the die has I/O cells that aren't bonded to any package pin. (e.g. TQFP-44 packages)\nNormally, these extra I/O cells are left as inputs,\nbut if inputs are allowed to float, this could cause excessive power usage,\nso the fitter turns them into outputs by setting the appropriate OE mux fuses.\n\n### `power_guard.sx` `(power_guard)`\nIn ZE-family devices, input signals can be \"masked\"\nso that high frequency signals don't propagate very far through the chip when not needed.\nThis can reduce dynamic power consumption.\nNormally, power guard is disabled when the GLB's shared enable PT is high.\nPower guard can also be permanently disabled for individual inputs using a fuse defined here.\nThat may be necessary if you need to use the shared enable PT for a GOE.\n\n### `osctimer.sx` `(osctimer)`\nZE-family devices contain a low-accuracy 5 MHz oscillator,\nand a divider that can drop it down to lower frequencies.\nWhen enabled, these signals replace the macrocell feedback signals for specific macrocells.\n\n\n# Fitter Bugs \u0026 Uncertainties\n\nIn the process of trying to get the LPF4k fitter to do what I want,\nI've encountered a handful of bugs,\nas well as some limitations which make it impossible to exercise certain hardware features.\nIn these cases, I've done my best to manually reverse engineer with real hardware,\nbut I don't have access to every device variant,\nso I've also had to make some assumptions.\nI'll try to document those here.\n\n### Fitter won't route all GOEs\nEven though there are four GOEs in every device,\nthe fitter will never route more than two of them in any particular design.\nIf you add more unique equations than that,\nit'll start using PT4 as individual OE for the extra ones.\nI tried adding a bunch of dummy logic product terms so that there isn't a free PT available,\nbut that doesn't convince it to do otherwise;\nit'll just shout about failing to allocate everything.\n\nIt's also impossible to force the fitter to place a shared PT OE in a specific GLB.\nThis means I've had to make some assumptions about the locations of the shared PT OE bus fuses,\nbut based on testing with LC4032ZE and LC4064ZC devices,\nI would be surprised if they don't hold for all devices.\n\n### Negated GOE signals\nWhen attempting to use a suffix of `.OE-` to create an active-low GOE,\nthe fitter report lists the correct equations,\nbut the JEDEC file that results is identical to one that just used `.OE`.\nIn order to coerce it to actually program the GOE polarity fuse,\nyou can invert the source signal instead,\nbut that only works when it's coming directly from an OE pin.\nOtherwise it will just use the complemented signal in the shared PT OE.\nThis means it's really only possible to locate two of the GOE polarity fuses per device.\nWe have to infer the locations of the others by assuming that they're all in a contiguous block.\n\n### Fitter won't set shared PT init polarity\nSomewhat similar to the bug above,\nthe fitter will refuse to route a design that uses `.AR-` or `.AS-`.\nPresumably this is because it's not able to invert the output of PT3 when that's used for initialization.\nBut when coming from the shared PT, there _is_ a configurable polarity;\nit's just impossible to get the fitter to use it.\nAs above, if you invert a single signal, it will just encode that in the shared PT itself.\nSo again, we have to infer the location of this fuse based on where we know the shared PT clock polarity fuse is,\nwith hardware testing for verification.\n\n### LC4128ZE_TQFP100 Missing Power Guard fuse for CLK0\nEnabling a power guard instance for this pin on this particular device does not cause any fuse to be written.\nThe fitter does not give any warnings however,\nand the dedicated clock power guard fuses for other package variants match this one,\nexcept for this one fuse.\nThis leads me to assume that one line in the fitter source code probably got deleted or something,\ncausing it to skip this fuse.\nI added a special case to force this to the fuse it (very likely) should be.\n\n### LC4064ZC_csBGA56 Dedicated Inputs\nThe datasheet lists that this device has 32 I/Os and 12 input-only pins (4 clocks and 8 dedicated inputs).\nI believe that two of the 8 dedicated inputs are actually just connected to regular macrocells.\n\nThere is quite a bit of evidence supporting this assumption:\n* No other LC4064 or LC4128 packages have more than 6 dedicated inputs, even though some devices (e.g. `LC4064ZC_csBGA132`) have unconnected pins.  One would think if the die actually had 8 dedicated inputs, they would connect them to pins when possible.\n* The LC4064s in TQFP-44 use a trick where only half the macrocells have corresponding I/O cells, resulting in a reduced JEDEC height of 95, but this device has a JEDEC height of 100, so internally it likely has the full complement of 64 I/O cells, with half of them unconnected.\n* The GI routing fuses used for ball F8 are exactly the same as the fuses for macrocell C12's I/O in packages that expose it.\n* The GI routing fuses used for ball E3 are exactly the same as the fuses for macrocell A15's I/O in packages that expose it.\n\nTherefore, in the `pins.csv` file, I've listed balls E3 and F8 as I/Os corresponding to macrocells A15 and C12, respectively.\nAttempting to assign these pins as outputs causes the fitter to spit out a warning,\nso there are some fuses that I can't reverse engineer using the fitter.\nIn these cases I'm just copying the fuse locations from the corresponding macrocell in the `LC4064ZC_TQFP100` package,\nunder the assumption that it uses the same die.\n\nAdditionally, there appears to be a fitter bug relating to the input threshold fuse for balls F8 and E1.\nThe fitter toggles two input threshold fuses for the input on ball E1,\nand no fuses for the input on ball F8.\nSince F8 is one of the \"weird\" dedicated inputs,\nI'm using the C12 macrocell's input threshold fuse from the TQFP100 package for that one,\njust like I do for the output configuration fuses.\nThen I can just exclude that fuse from the fuses the fitter toggled for ball E1,\nwhich yields only one remaining correct fuse for that ball.\n\nI don't have any of these devices to test physically, so to be safe,\nyou may just want to avoid using balls E1, E3, and F8 entirely for this particular device.\n\n### Fitter Report missing GI data\nFor `LC4064ZC_csBGA56`, the second column (GIs 18-35) doesn't always show up in the fitter GI summary.\nFor some other devices, \"input only\" pins are incorrectly listed as sourced from a macrocell feedback signal.\ne.g. for `LC4128ZC_TQFP100`, pin 12's source is listed as \"mc B-11\",\nbut the GI mux fuse that's set is one of the ones corresponding to pin 16 in `LC4128V_TQFP144`;\nwhich is MC B14 and ORP B^11 in that device.\nSo it seems the fitter is writing the I/O cell's ID in this case, rather than the actual pin number.\n\n## Glossary\n\n#### GLB\nGeneric Logic Block: A group of 36 GIs, 83 PTs, 16 MCs, and the other logic associated with them.  Each device contains two or more GLBs.\n\n#### GRP\nGlobal Routing Pool: the set of all signals that can be used as inputs to a GLB.  This includes all I/O cell pins, feedback from all MCs, dedicated clock pins, and (in some devices) dedicated input pins.\n\n#### GI\nGeneric Input: One of 36 signals per GLB which can be used in that GLB's product terms.\n\n#### PT\nProduct Term: Up to 36 signals (or their complements) ANDed together.\n\n#### MC\nMacrocell: A single flip-flop or combinational logic \"output\".\n\n#### MC Slice\nMacrocell Slice: A 5-PT cluster, macrocell, routing logic, and I/O cell.  Each GLB contains 16 MC Slices, along with the 3 shared PTs, BCLK and GI configuration.\n\n#### ORM\nOutput Routing Multiplexer: Allows macrocells and their associated OE product term to be shunted to a different nearby pin.\n\n#### BCLK\nBlock Clock: Each GLB (\"Block\") can independently configure the polarity of the dedicated clock inputs.\n\n#### BIE\nBlock Input Enable: For ZE-family devices, inputs can be dynamically masked to reduce dynamic power consumption.\n\n#### GOE\nGlobal Output Enable: Up to four signals which can come from specific input pins, or from the BIE shared PTs.\n\n#### CE\nClock Enable\n\n#### LE\nLatch Enable\n\n#### AS\nAsynchronous (pre)Set\n\n#### AR\nAsynchronous Reset/clear\n\n## Reproduction Steps\n\nIn case you want to try to add other devices, or just want to reproduce the .sx files that are committed here, you can follow these build steps:\n\n1. Make sure ispLEVER Classic 2.1 is installed at `C:\\ispLEVER_Classic2_1` and that you have a valid license.  In particular, `C:\\ispLEVER_Classic2_1\\ispcpld\\bin\\lpf4k.exe` needs to work, but nothing else is used.\n2. Make sure Zig is installed and run `zig build -Doptimize=ReleaseSafe` from the `generate/` directory.\n3. (optional) Make sure LIMP is installed and run `limp -R .` from the root of the repo.  This will regenerate the Ninja makefiles.\n4. Make sure Ninja is installed and run `ninja` from the root of the repo.\n\nNote: a large number of temporary files are created (and then deleted) in the `temp/` directory.  I found that adding a Windows Defender exclusion for the repo and the `ispLEVER_Classic2_1` directory significantly speeds up the process.\n\n# TODO\n* Hardware experiments\n    * Why are there two fuses to enable the OSCTIMER? what happens if only one is enabled? (or none, but divider/outputs are enabled)\n    * Do OSCTIMER outputs only replace the GRP feedback signals when enabled, or also the signal that goes to the ORM?\n    * Can you use input register feedback on MCs that aren't connected to pins? (e.g. LC4064x TQFP48)\n    * What happens if you violate the one-cold rule for GI fuses?","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbcrist%2Fre4k","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbcrist%2Fre4k","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbcrist%2Fre4k/lists"}