aboutsummaryrefslogtreecommitdiffstats
path: root/misc/yosys.proto
blob: a583e6265cf2b2eb823fdf108821eb7063f6859e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//
// yosys -- Yosys Open SYnthesis Suite
//
// Copyright (C) 2018  Serge Bazanski <q3k@symbioticeda.com>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

/// Protobuf definition of Yosys RTLIL dump/restore format for RTL designs.

syntax = "proto3";

package yosys.pb;

// Port direction.
enum Direction {
    DIRECTION_INVALID = 0;
    DIRECTION_INPUT = 1;
    DIRECTION_OUTPUT = 2;
    DIRECTION_INOUT = 3;
}

// A freeform parameter/attribute value.
message Parameter {
    oneof value {
        int64 int = 1;
        string str = 2;
    }
}

// A signal in the design - either a unique identifier for one, or a constant
// driver (low or high).
message Signal {
    // A constant signal driver in the design.
    enum ConstantDriver {
        CONSTANT_DRIVER_INVALID = 0;
        CONSTANT_DRIVER_LOW = 1;
        CONSTANT_DRIVER_HIGH = 2;
        CONSTANT_DRIVER_Z = 3;
        CONSTANT_DRIVER_X = 4;
    }
    oneof type {
        // Signal uniquely identified by ID number.
        int64 id = 1;
        // Constant driver.
        ConstantDriver constant = 2;
    }
}

// A vector of signals.
message BitVector {
    repeated Signal signal = 1;
}

// A netlist module.
message Module {
    // Freeform attributes.
    map<string, Parameter> attribute = 1;

    // Named ports in this module.
    message Port {
        Direction direction = 1;
        BitVector bits = 2;
    }
    map<string, Port> port = 2;

    // Named cells in this module.
    message Cell {
        // Set to true when the name of this cell is automatically created and
        // likely not of interest for a regular user.
        bool hide_name = 1;
        string type = 2;
        // Set if this module has an AIG model available.
        string model = 3;
        // Freeform parameters.
        map<string, Parameter> parameter = 4;
        // Freeform attributes.
        map<string, Parameter> attribute = 5;

        /// Ports of the cell.
        // Direction of the port, if interface is known.
        map<string, Direction> port_direction = 6;
        // Connection of named port to signal(s).
        map<string, BitVector> connection = 7;
    }
    map<string, Cell> cell = 3;

    // Nets in this module.
    message Netname {
        // Set to true when the name of this net is automatically created and
        // likely not of interest for a regular user.
        bool hide_name = 1;
        // Signal(s) that make up this net.
        BitVector bits = 2;
        // Freeform attributes.
        map<string, Parameter> attributes = 3;
    }
    repeated Netname netname = 4;
}

// And-Inverter-Graph model.
message Model {
    message Node {
        // Type of AIG node - or, what its' value is.
        enum Type {
            TYPE_INVALID = 0;
            // The node's value is the value of the specified input port bit.
            TYPE_PORT = 1;
            // The node's value is the inverted value of the specified input
            // port bit.
            TYPE_NPORT = 2;
            // The node's value is the ANDed value of specified nodes.
            TYPE_AND = 3;
            // The node's value is the NANDed value of specified nodes.
            TYPE_NAND = 4;
            // The node's value is a constant 1.
            TYPE_TRUE = 5;
            // The node's value is a constant 0.
            TYPE_FALSE = 6;
        };
        Type type = 1;

        message Port {
            // Name of port.
            string portname = 1;
            // Bit index in port.
            int64 bitindex = 2;
        }
        message Gate {
            // Node index of left side of operation.
            int64 left = 1;
            // Node index of right side of operation.
            int64 right = 2;
        }
        oneof node {
            // Set for PORT, NPORT
            Port port = 2;
            // Set for AND, NAND.
            Gate gate = 3;
        }

        // Set when the node drives given output port(s).
        message OutPort {
            // Name of port.
            string name = 1;
            // Bit index in port.
            int64 bit_index = 2;
        }
        repeated OutPort out_port = 4;
    }

    // List of  AIG nodes - each is explicitely numbered by its' index in this
    // array.
    repeated Node node = 1;
}

// A Yosys design netlist dumped from RTLIL.
message Design {
    // Human-readable freeform 'remark' string.
    string creator = 1;
    // List of named modules in design.
    map<string, Module> modules = 2;
    // List of named AIG models in design (if AIG export enabled).
    map<string, Model> models = 3;
}
n> ### Advanced Macros In addition to the `process_record_user()` function, is the `post_process_record_user()` function. This runs after `process_record` and can be used to do things after a keystroke has been sent. This is useful if you want to have a key pressed before and released after a normal key, for instance. In this example, we modify most normal keypresses so that `F22` is pressed before the keystroke is normally sent, and release it __only after__ it's been released. ```c static uint8_t f22_tracker; bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case KC_A ... KC_F21: //notice how it skips over F22 case KC_F23 ... KC_EXSEL: //exsel is the last one before the modifier keys if (record->event.pressed) { register_code(KC_F22); //this means to send F22 down f22_tracker++; register_code(keycode); return false; } break; } return true; } void post_process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case KC_A ... KC_F21: //notice how it skips over F22 case KC_F23 ... KC_EXSEL: //exsel is the last one before the modifier keys if (!record->event.pressed) { f22_tracker--; if (!f22_tracker) { unregister_code(KC_F22); //this means to send F22 up } } break; } } ``` ### TAP, DOWN and UP You may want to use keys in your macros that you can't write down, such as `Ctrl` or `Home`. You can send arbitrary keycodes by wrapping them in: * `SS_TAP()` presses and releases a key. * `SS_DOWN()` presses (but does not release) a key. * `SS_UP()` releases a key. For example: SEND_STRING(SS_TAP(X_HOME)); Would tap `KC_HOME` - note how the prefix is now `X_`, and not `KC_`. You can also combine this with other strings, like this: SEND_STRING("VE"SS_TAP(X_HOME)"LO"); Which would send "VE" followed by a `KC_HOME` tap, and "LO" (spelling "LOVE" if on a newline). Delays can be also added to the string: * `SS_DELAY(msecs)` will delay for the specified number of milliseconds. For example: SEND_STRING("VE" SS_DELAY(1000) SS_TAP(X_HOME) "LO"); Which would send "VE" followed by a 1-second delay, then a `KC_HOME` tap, and "LO" (spelling "LOVE" if on a newline, but delayed in the middle). There's also a couple of mod shortcuts you can use: * `SS_LCTL(string)` * `SS_LSFT(string)` * `SS_LALT(string)` or `SS_LOPT(string)` * `SS_LGUI(string)`, `SS_LCMD(string)` or `SS_LWIN(string)` * `SS_RCTL(string)` * `SS_RSFT(string)` * `SS_RALT(string)`, `SS_ROPT(string)` or `SS_ALGR(string)` * `SS_RGUI(string)`, `SS_RCMD(string)` or `SS_RWIN(string)` These press the respective modifier, send the supplied string and then release the modifier. They can be used like this: SEND_STRING(SS_LCTL("a")); Which would send Left Control+`a` (Left Control down, `a`, Left Control up) - notice that they take strings (eg `"k"`), and not the `X_K` keycodes. ### Alternative Keymaps By default, it assumes a US keymap with a QWERTY layout; if you want to change that (e.g. if your OS uses software Colemak), include this somewhere in your keymap: #include <sendstring_colemak.h> ### Strings in Memory If for some reason you're manipulating strings and need to print out something you just generated (instead of being a literal, constant string), you can use `send_string()`, like this: ```c char my_str[4] = "ok."; send_string(my_str); ``` The shortcuts defined above won't work with `send_string()`, but you can separate things out to different lines if needed: ```c char my_str[4] = "ok."; SEND_STRING("I said: "); send_string(my_str); SEND_STRING(".."SS_TAP(X_END)); ``` ## Advanced Macro Functions There are some functions you may find useful in macro-writing. Keep in mind that while you can write some fairly advanced code within a macro, if your functionality gets too complex you may want to define a custom keycode instead. Macros are meant to be simple. ?> You can also use the functions described in [Useful function](ref_functions.md) for additional functionality. For example `reset_keyboard()` allows you to reset the keyboard as part of a macro. ### `record->event.pressed` This is a boolean value that can be tested to see if the switch is being pressed or released. An example of this is ```c if (record->event.pressed) { // on keydown } else { // on keyup } ``` ### `register_code(<kc>);` This sends the `<kc>` keydown event to the computer. Some examples would be `KC_ESC`, `KC_C`, `KC_4`, and even modifiers such as `KC_LSFT` and `KC_LGUI`. ### `unregister_code(<kc>);` Parallel to `register_code` function, this sends the `<kc>` keyup event to the computer. If you don't use this, the key will be held down until it's sent. ### `tap_code(<kc>);` This will send `register_code(<kc>)` and then `unregister_code(<kc>)`. This is useful if you want to send both the press and release events ("tap" the key, rather than hold it). If you're having issues with taps (un)registering, you can add a delay between the register and unregister events by setting `#define TAP_CODE_DELAY 100` in your `config.h` file. The value is in milliseconds. ### `register_code16(<kc>);`, `unregister_code16(<kc>);` and `tap_code16(<kc>);` These functions work similar to their regular counterparts, but allow you to use modded keycodes (with Shift, Alt, Control, and/or GUI applied to them). Eg, you could use `register_code16(S(KC_5));` instead of registering the mod, then registering the keycode. ### `clear_keyboard();` This will clear all mods and keys currently pressed. ### `clear_mods();` This will clear all mods currently pressed. ### `clear_keyboard_but_mods();` This will clear all keys besides the mods currently pressed. ## Advanced Example: ### Super ALT↯TAB This macro will register `KC_LALT` and tap `KC_TAB`, then wait for 1000ms. If the key is tapped again, it will send another `KC_TAB`; if there is no tap, `KC_LALT` will be unregistered, thus allowing you to cycle through windows. ```c bool is_alt_tab_active = false; # ADD this near the begining of keymap.c uint16_t alt_tab_timer = 0; # we will be using them soon. enum custom_keycodes { # Make sure have the awesome keycode ready ALT_TAB = SAFE_RANGE, }; bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { # This will do most of the grunt work with the keycodes. case ALT_TAB: if (record->event.pressed) { if (!is_alt_tab_active) { is_alt_tab_active = true; register_code(KC_LALT); } alt_tab_timer = timer_read(); register_code(KC_TAB); } else { unregister_code(KC_TAB); } break; } return true; } void matrix_scan_user(void) { # The very important timer. if (is_alt_tab_active) { if (timer_elapsed(alt_tab_timer) > 1000) { unregister_code(KC_LALT); is_alt_tab_active = false; } } } ``` --- ## **(DEPRECATED)** The Old Way: `MACRO()` & `action_get_macro` !> This is inherited from TMK, and hasn't been updated - it's recommended that you use `SEND_STRING` and `process_record_user` instead. By default QMK assumes you don't have any macros. To define your macros you create an `action_get_macro()` function. For example: ```c const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { if (record->event.pressed) { switch(id) { case 0: return MACRO(D(LSFT), T(H), U(LSFT), T(I), D(LSFT), T(1), U(LSFT), END); case 1: return MACRO(D(LSFT), T(B), U(LSFT), T(Y), T(E), D(LSFT), T(1), U(LSFT), END); } } return MACRO_NONE; }; ``` This defines two macros which will be run when the key they are assigned to is pressed. If instead you'd like them to run when the key is released you can change the if statement: if (!record->event.pressed) { ### Macro Commands A macro can include the following commands: * I() change interval of stroke in milliseconds. * D() press key. * U() release key. * T() type key(press and release). * W() wait (milliseconds). * END end mark. ### Mapping a Macro to a Key Use the `M()` function within your keymap to call a macro. For example, here is the keymap for a 2-key keyboard: ```c const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [0] = LAYOUT( M(0), M(1) ), }; const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { if (record->event.pressed) { switch(id) { case 0: return MACRO(D(LSFT), T(H), U(LSFT), T(I), D(LSFT), T(1), U(LSFT), END); case 1: return MACRO(D(LSFT), T(B), U(LSFT), T(Y), T(E), D(LSFT), T(1), U(LSFT), END); } } return MACRO_NONE; }; ``` When you press the key on the left it will type "Hi!" and when you press the key on the right it will type "Bye!". ### Naming Your Macros If you have a bunch of macros you want to refer to from your keymap while keeping the keymap easily readable you can name them using `#define` at the top of your file. ```c #define M_HI M(0) #define M_BYE M(1) const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [0] = LAYOUT( M_HI, M_BYE ), }; ``` ## Advanced Example: ### Single-Key Copy/Paste This example defines a macro which sends `Ctrl-C` when pressed down, and `Ctrl-V` when released. ```c const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { switch(id) { case 0: { if (record->event.pressed) { return MACRO( D(LCTL), T(C), U(LCTL), END ); } else { return MACRO( D(LCTL), T(V), U(LCTL), END ); } break; } } return MACRO_NONE; }; ```