{"action":"created","comment":{"url":"https://api.github.com/repos/maxeler/maxpower/pulls/comments/45469679","id":45469679,"diff_hunk":"@@ -0,0 +1,170 @@\n+package maxpower.kernel.mem;\n+\n+import java.util.ArrayList;\n+import java.util.Arrays;\n+import java.util.HashSet;\n+import java.util.List;\n+import java.util.Set;\n+\n+import maxpower.kernel.io.VariableWidthIO;\n+\n+import com.maxeler.maxcompiler.v2.errors.MaxCompilerAPIError;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.KernelLib;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.stdlib.Bitops;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.stdlib.core.Mem.RamWriteMode;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.stdlib.memory.Memory;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.types.KernelObjectVectorizable;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.types.KernelType;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.types.base.DFEVar;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.types.composite.DFEStruct;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.types.composite.DFEVector;\n+import com.maxeler.maxcompiler.v2.kernelcompiler.types.composite.DFEVectorType;\n+import com.maxeler.maxcompiler.v2.utils.MathUtils;\n+\n+/**\n+ *   This implements multi-bank FMEM buffer with a scheduled access.\n+ *   Multiple inputs and outputs per cycle are supported. The number of banks\n+ *   in FMEM may exceed the number of inputs/outputs. Each input and output\n+ *   entry is supported by its own scheduling command instructing which FMEM\n+ *   bank to read/write at which address.\n+ *\n+ *\n+ *   @author Pavel Burovskiy\n+ */\n+class ScheduledAccessBuffer<T extends KernelObjectVectorizable<T,?>> extends KernelLib\n+{\n+    private final List<Memory<T>> buffer;\n+    private final DFEVector<T> output;\n+\n+    public DFEVector<T> getOutput() { return output; }\n+\n+    /***\n+     *  Create scheduled access buffer for which the number of\n+     *  inputs and outputs equal AND write access schedule simultaneously\n+     *  works as read access schedule: data is put into the buffer for the\n+     *  purpose of the further re-use, but the same data must also\n+     *  appear at the output same cycle. Read and write access\n+     *  schedulings are merged into one, with an additional read/write\n+     *  boolean flag per scheduling command: 'write' state implies both\n+     *  read and write access; 'read' state implies only reads from FMEM.\n+     *  <p>\n+     *  Inputs and outputs are DFEVectors of same size, also the same size as\n+     *  DFEVector of scheduling commands. If <i>n</i> scheduling commands says\n+     *  'write' and <i>m</i> commands says 'read', only first <i>n</i>\n+     *  elements of input vector are put into FMEM (accessed in order of their\n+     *  reference by 'write' scheduling commands); the last <i>m</i> elements\n+     *  of input vector are <i>ignored</i>. Please use {@link VariableWidthIO}\n+     *  to read variable number of necessary items per cycle, to form the\n+     *  input to this buffer. The output elements come in order of their\n+     *  reference by both read and write schedule commands.\n+     *  <p>\n+     *  Scheduling command is a DFEStruct which must have the following fields:\n+     *  <ul>\n+     *     <li> buffID: the FMEM bank to access; </li>\n+     *     <li> buffIndex: address within the FMEM bank; </li>\n+     *     <li> buffRW: boolean flag, as above. </li>\n+     *  </ul>\n+     *  It may have other fields (ignored by this buffer). Scheduling must\n+     *  comply with the following rules:\n+     *  <p>\n+     *  <ul>\n+     *     <li> If several scheduling commands point to the same FMEM bank,\n+     *          all must have same address, and at most one command is marked 'write'.</li>\n+     *     <li> No two write commands use the same FMEM bank.</li>\n+     *  </ul>\n+     *  Non-conforming scheduling implies undefined behaviour.\n+     *  <p>\n+     *  @param  numBufs      number of FMEM banks\n+     *  @param  bufDepth     (maximum) number of entries in each FMEM bank\n+     *  @param  dataType     type of stored data\n+     *  @param  dataIn       vector of input data\n+     *  @param  scheduling   vector of scheduling commands\n+     *  @return DFEVector of data buffered\n+     *  @throws MaxCompilerAPIError  If number of inputs does not match number of scheduling commands\n+     *  @throws MaxCompilerAPIError  If number of inputs exceeds the number of FMEM banks\n+     *  @throws MaxCompilerAPIError  If number of inputs is zero\n+     *  @throws MaxCompilerAPIError  If scheduling command does not have necessary fields\n+     */\n+    ScheduledAccessBuffer(KernelLib owner, int numBufs, int bufDepth, KernelType<T> dataType,\n+                DFEVector<T> dataIn, DFEVector<DFEStruct> scheduling){\n+        super(owner);\n+\n+        int numInputs = scheduling.getSize();\n+        int numOutputs = scheduling.getSize();\n+        if (numInputs > numBufs )\n+            throw new MaxCompilerAPIError(\"Number of FMEM banks must be greater or equal the number of scheduling commands\");\n+        if (numInputs < 1)\n+            throw new MaxCompilerAPIError(\"Number of input data items must be greater than 0\");\n+        if (dataIn.getSize() != numInputs)\n+            throw new MaxCompilerAPIError(\"Number of input data items must equal the number of scheduling commands\");\n+        Set<String> fieldNames = scheduling[0].getType().getFieldNames();\n+        Set<String> minimalSetOfFields = new HashSet<String>(Arrays.asList(\"buffID\",\"buffIndex\",\"buffRW\"));\n+        if (!fieldNames.containsAll(minimalSetOfFields))\n+            throw new MaxCompilerAPIError(\"scheduling commands must have the following fields:\" + minimalSetOfFields.toString());\n+\n+        int bufferAddressBits = MathUtils.bitsToAddress(bufDepth);\n+        DFEVectorType<DFEVar> selectorType = new DFEVectorType<DFEVar>(dfeBool(), numInputs);\n+\n+        buffer = new ArrayList<Memory<T>>(numBufs);\n+        for (int i = 0; i < numBufs; i++)\n+        {\n+            buffer.add(mem.alloc(dataType, bufDepth));\n+        }\n+\n+        DFEVector<T> dataFromBRAMs = new DFEVectorType<T>(dataType, numBufs).newInstance(this);\n+        for (int i = 0; i < numBufs; i++)\n+        {\n+            /*\n+             *  Num inputs does not match num buffers =>\n+             *  do match buffer ids with the list of available buffers:\n+             *  preparing for accessing the row of BRAM buffers\n+             */\n+            DFEVector<DFEVar> readSelector = selectorType.newInstance(this);\n+            DFEVector<DFEVar> writeSelector = selectorType.newInstance(this);\n+            for (int j = 0; j < numInputs; j++)\n+            {\n+                DFEVar bufferIdsMatch = ((DFEVar)scheduling[j][\"buffID\"]).eq(i);\n+\n+                // Just in case this component has other values\n+                DFEVar scheduleSaysWrite = ((DFEVar)scheduling[j][\"buffRW\"]).eq(1);\n+                DFEVar scheduleSaysRead  = ((DFEVar)scheduling[j][\"buffRW\"]).eq(0);\n+                DFEVar bothReadAndWrite  = scheduleSaysRead | scheduleSaysWrite;\n+                // Assuming CPU scheduling does not allow 2 mem commands to write to the same BRAM buf\n+                writeSelector[j] <== bufferIdsMatch & scheduleSaysWrite;\n+                // Reading from a BRAM in either case\n+                readSelector[j] <== bufferIdsMatch & bothReadAndWrite;\n+            }\n+\n+            // TODO: possible optimisation: shift vector elements so that required element has index 0\n+            DFEVar writeSelect = writeSelector.pack();\n+            DFEStruct writeMemCommandPerBRAM = control.oneHotMux(writeSelect, scheduling.getElementsAsList());\n+            // If neither mem cmd references this BRAM, make sure we don't write to it\n+            DFEVar writeEnable = writeSelect.neq(0) & ((DFEVar)writeMemCommandPerBRAM[\"buffRW\"]).eq(1);\n+            T dataToWrite = control.oneHotMux(writeSelect, dataIn.getElementsAsList());\n+\n+            // If more than one mem cmd request to access this (i-th) BRAM, choose one;\n+            // for the sake of convention, choose memcmd with largest id number\n+            DFEVar readSelectorPacked = readSelector.pack();\n+            DFEVar oneHotReadSelect = readSelectorPacked.cast(dfeUInt(numInputs));","path":"src/maxpower/kernel/mem/ScheduledAccessBuffer.maxj","position":148,"original_position":148,"commit_id":"37d68c017bb060339234a9ce567489cf320b8db5","original_commit_id":"37d68c017bb060339234a9ce567489cf320b8db5","user":{"login":"stepeh","id":12087956,"avatar_url":"https://avatars.githubusercontent.com/u/12087956?v=3","gravatar_id":"","url":"https://api.github.com/users/stepeh","html_url":"https://github.com/stepeh","followers_url":"https://api.github.com/users/stepeh/followers","following_url":"https://api.github.com/users/stepeh/following{/other_user}","gists_url":"https://api.github.com/users/stepeh/gists{/gist_id}","starred_url":"https://api.github.com/users/stepeh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stepeh/subscriptions","organizations_url":"https://api.github.com/users/stepeh/orgs","repos_url":"https://api.github.com/users/stepeh/repos","events_url":"https://api.github.com/users/stepeh/events{/privacy}","received_events_url":"https://api.github.com/users/stepeh/received_events","type":"User","site_admin":false},"body":"No, I mean DFEType.unpack() (it is the opposite of pack).\r\n","created_at":"2015-11-20T13:48:14Z","updated_at":"2015-11-20T13:48:14Z","html_url":"https://github.com/maxeler/maxpower/pull/43#discussion_r45469679","pull_request_url":"https://api.github.com/repos/maxeler/maxpower/pulls/43","_links":{"self":{"href":"https://api.github.com/repos/maxeler/maxpower/pulls/comments/45469679"},"html":{"href":"https://github.com/maxeler/maxpower/pull/43#discussion_r45469679"},"pull_request":{"href":"https://api.github.com/repos/maxeler/maxpower/pulls/43"}}},"pull_request":{"url":"https://api.github.com/repos/maxeler/maxpower/pulls/43","id":51294505,"html_url":"https://github.com/maxeler/maxpower/pull/43","diff_url":"https://github.com/maxeler/maxpower/pull/43.diff","patch_url":"https://github.com/maxeler/maxpower/pull/43.patch","issue_url":"https://api.github.com/repos/maxeler/maxpower/issues/43","number":43,"state":"open","locked":false,"title":"Adding a scheduled access multi-bank FMEM buffer","user":{"login":"burchanie","id":7000687,"avatar_url":"https://avatars.githubusercontent.com/u/7000687?v=3","gravatar_id":"","url":"https://api.github.com/users/burchanie","html_url":"https://github.com/burchanie","followers_url":"https://api.github.com/users/burchanie/followers","following_url":"https://api.github.com/users/burchanie/following{/other_user}","gists_url":"https://api.github.com/users/burchanie/gists{/gist_id}","starred_url":"https://api.github.com/users/burchanie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/burchanie/subscriptions","organizations_url":"https://api.github.com/users/burchanie/orgs","repos_url":"https://api.github.com/users/burchanie/repos","events_url":"https://api.github.com/users/burchanie/events{/privacy}","received_events_url":"https://api.github.com/users/burchanie/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-11-19T22:59:02Z","updated_at":"2015-11-20T13:48:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f6f44e64c7771639a624e1900a4e6b83a16ef19e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/maxeler/maxpower/pulls/43/commits","review_comments_url":"https://api.github.com/repos/maxeler/maxpower/pulls/43/comments","review_comment_url":"https://api.github.com/repos/maxeler/maxpower/pulls/comments{/number}","comments_url":"https://api.github.com/repos/maxeler/maxpower/issues/43/comments","statuses_url":"https://api.github.com/repos/maxeler/maxpower/statuses/37d68c017bb060339234a9ce567489cf320b8db5","head":{"label":"burchanie:feature/scheduledbuffer","ref":"feature/scheduledbuffer","sha":"37d68c017bb060339234a9ce567489cf320b8db5","user":{"login":"burchanie","id":7000687,"avatar_url":"https://avatars.githubusercontent.com/u/7000687?v=3","gravatar_id":"","url":"https://api.github.com/users/burchanie","html_url":"https://github.com/burchanie","followers_url":"https://api.github.com/users/burchanie/followers","following_url":"https://api.github.com/users/burchanie/following{/other_user}","gists_url":"https://api.github.com/users/burchanie/gists{/gist_id}","starred_url":"https://api.github.com/users/burchanie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/burchanie/subscriptions","organizations_url":"https://api.github.com/users/burchanie/orgs","repos_url":"https://api.github.com/users/burchanie/repos","events_url":"https://api.github.com/users/burchanie/events{/privacy}","received_events_url":"https://api.github.com/users/burchanie/received_events","type":"User","site_admin":false},"repo":{"id":46135627,"name":"maxpower","full_name":"burchanie/maxpower","owner":{"login":"burchanie","id":7000687,"avatar_url":"https://avatars.githubusercontent.com/u/7000687?v=3","gravatar_id":"","url":"https://api.github.com/users/burchanie","html_url":"https://github.com/burchanie","followers_url":"https://api.github.com/users/burchanie/followers","following_url":"https://api.github.com/users/burchanie/following{/other_user}","gists_url":"https://api.github.com/users/burchanie/gists{/gist_id}","starred_url":"https://api.github.com/users/burchanie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/burchanie/subscriptions","organizations_url":"https://api.github.com/users/burchanie/orgs","repos_url":"https://api.github.com/users/burchanie/repos","events_url":"https://api.github.com/users/burchanie/events{/privacy}","received_events_url":"https://api.github.com/users/burchanie/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/burchanie/maxpower","description":"Maxeler standard library","fork":true,"url":"https://api.github.com/repos/burchanie/maxpower","forks_url":"https://api.github.com/repos/burchanie/maxpower/forks","keys_url":"https://api.github.com/repos/burchanie/maxpower/keys{/key_id}","collaborators_url":"https://api.github.com/repos/burchanie/maxpower/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/burchanie/maxpower/teams","hooks_url":"https://api.github.com/repos/burchanie/maxpower/hooks","issue_events_url":"https://api.github.com/repos/burchanie/maxpower/issues/events{/number}","events_url":"https://api.github.com/repos/burchanie/maxpower/events","assignees_url":"https://api.github.com/repos/burchanie/maxpower/assignees{/user}","branches_url":"https://api.github.com/repos/burchanie/maxpower/branches{/branch}","tags_url":"https://api.github.com/repos/burchanie/maxpower/tags","blobs_url":"https://api.github.com/repos/burchanie/maxpower/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/burchanie/maxpower/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/burchanie/maxpower/git/refs{/sha}","trees_url":"https://api.github.com/repos/burchanie/maxpower/git/trees{/sha}","statuses_url":"https://api.github.com/repos/burchanie/maxpower/statuses/{sha}","languages_url":"https://api.github.com/repos/burchanie/maxpower/languages","stargazers_url":"https://api.github.com/repos/burchanie/maxpower/stargazers","contributors_url":"https://api.github.com/repos/burchanie/maxpower/contributors","subscribers_url":"https://api.github.com/repos/burchanie/maxpower/subscribers","subscription_url":"https://api.github.com/repos/burchanie/maxpower/subscription","commits_url":"https://api.github.com/repos/burchanie/maxpower/commits{/sha}","git_commits_url":"https://api.github.com/repos/burchanie/maxpower/git/commits{/sha}","comments_url":"https://api.github.com/repos/burchanie/maxpower/comments{/number}","issue_comment_url":"https://api.github.com/repos/burchanie/maxpower/issues/comments{/number}","contents_url":"https://api.github.com/repos/burchanie/maxpower/contents/{+path}","compare_url":"https://api.github.com/repos/burchanie/maxpower/compare/{base}...{head}","merges_url":"https://api.github.com/repos/burchanie/maxpower/merges","archive_url":"https://api.github.com/repos/burchanie/maxpower/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/burchanie/maxpower/downloads","issues_url":"https://api.github.com/repos/burchanie/maxpower/issues{/number}","pulls_url":"https://api.github.com/repos/burchanie/maxpower/pulls{/number}","milestones_url":"https://api.github.com/repos/burchanie/maxpower/milestones{/number}","notifications_url":"https://api.github.com/repos/burchanie/maxpower/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/burchanie/maxpower/labels{/name}","releases_url":"https://api.github.com/repos/burchanie/maxpower/releases{/id}","created_at":"2015-11-13T17:04:53Z","updated_at":"2015-11-13T17:04:54Z","pushed_at":"2015-11-19T22:55:24Z","git_url":"git://github.com/burchanie/maxpower.git","ssh_url":"git@github.com:burchanie/maxpower.git","clone_url":"https://github.com/burchanie/maxpower.git","svn_url":"https://github.com/burchanie/maxpower","homepage":null,"size":2364,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"maxeler:master","ref":"master","sha":"568f57287819a62854e288311324aaaa3153890b","user":{"login":"maxeler","id":10088478,"avatar_url":"https://avatars.githubusercontent.com/u/10088478?v=3","gravatar_id":"","url":"https://api.github.com/users/maxeler","html_url":"https://github.com/maxeler","followers_url":"https://api.github.com/users/maxeler/followers","following_url":"https://api.github.com/users/maxeler/following{/other_user}","gists_url":"https://api.github.com/users/maxeler/gists{/gist_id}","starred_url":"https://api.github.com/users/maxeler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maxeler/subscriptions","organizations_url":"https://api.github.com/users/maxeler/orgs","repos_url":"https://api.github.com/users/maxeler/repos","events_url":"https://api.github.com/users/maxeler/events{/privacy}","received_events_url":"https://api.github.com/users/maxeler/received_events","type":"Organization","site_admin":false},"repo":{"id":27921920,"name":"maxpower","full_name":"maxeler/maxpower","owner":{"login":"maxeler","id":10088478,"avatar_url":"https://avatars.githubusercontent.com/u/10088478?v=3","gravatar_id":"","url":"https://api.github.com/users/maxeler","html_url":"https://github.com/maxeler","followers_url":"https://api.github.com/users/maxeler/followers","following_url":"https://api.github.com/users/maxeler/following{/other_user}","gists_url":"https://api.github.com/users/maxeler/gists{/gist_id}","starred_url":"https://api.github.com/users/maxeler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maxeler/subscriptions","organizations_url":"https://api.github.com/users/maxeler/orgs","repos_url":"https://api.github.com/users/maxeler/repos","events_url":"https://api.github.com/users/maxeler/events{/privacy}","received_events_url":"https://api.github.com/users/maxeler/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/maxeler/maxpower","description":"Maxeler standard library","fork":false,"url":"https://api.github.com/repos/maxeler/maxpower","forks_url":"https://api.github.com/repos/maxeler/maxpower/forks","keys_url":"https://api.github.com/repos/maxeler/maxpower/keys{/key_id}","collaborators_url":"https://api.github.com/repos/maxeler/maxpower/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/maxeler/maxpower/teams","hooks_url":"https://api.github.com/repos/maxeler/maxpower/hooks","issue_events_url":"https://api.github.com/repos/maxeler/maxpower/issues/events{/number}","events_url":"https://api.github.com/repos/maxeler/maxpower/events","assignees_url":"https://api.github.com/repos/maxeler/maxpower/assignees{/user}","branches_url":"https://api.github.com/repos/maxeler/maxpower/branches{/branch}","tags_url":"https://api.github.com/repos/maxeler/maxpower/tags","blobs_url":"https://api.github.com/repos/maxeler/maxpower/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/maxeler/maxpower/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/maxeler/maxpower/git/refs{/sha}","trees_url":"https://api.github.com/repos/maxeler/maxpower/git/trees{/sha}","statuses_url":"https://api.github.com/repos/maxeler/maxpower/statuses/{sha}","languages_url":"https://api.github.com/repos/maxeler/maxpower/languages","stargazers_url":"https://api.github.com/repos/maxeler/maxpower/stargazers","contributors_url":"https://api.github.com/repos/maxeler/maxpower/contributors","subscribers_url":"https://api.github.com/repos/maxeler/maxpower/subscribers","subscription_url":"https://api.github.com/repos/maxeler/maxpower/subscription","commits_url":"https://api.github.com/repos/maxeler/maxpower/commits{/sha}","git_commits_url":"https://api.github.com/repos/maxeler/maxpower/git/commits{/sha}","comments_url":"https://api.github.com/repos/maxeler/maxpower/comments{/number}","issue_comment_url":"https://api.github.com/repos/maxeler/maxpower/issues/comments{/number}","contents_url":"https://api.github.com/repos/maxeler/maxpower/contents/{+path}","compare_url":"https://api.github.com/repos/maxeler/maxpower/compare/{base}...{head}","merges_url":"https://api.github.com/repos/maxeler/maxpower/merges","archive_url":"https://api.github.com/repos/maxeler/maxpower/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/maxeler/maxpower/downloads","issues_url":"https://api.github.com/repos/maxeler/maxpower/issues{/number}","pulls_url":"https://api.github.com/repos/maxeler/maxpower/pulls{/number}","milestones_url":"https://api.github.com/repos/maxeler/maxpower/milestones{/number}","notifications_url":"https://api.github.com/repos/maxeler/maxpower/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/maxeler/maxpower/labels{/name}","releases_url":"https://api.github.com/repos/maxeler/maxpower/releases{/id}","created_at":"2014-12-12T13:40:35Z","updated_at":"2015-10-13T09:44:13Z","pushed_at":"2015-11-20T10:22:37Z","git_url":"git://github.com/maxeler/maxpower.git","ssh_url":"git@github.com:maxeler/maxpower.git","clone_url":"https://github.com/maxeler/maxpower.git","svn_url":"https://github.com/maxeler/maxpower","homepage":null,"size":2595,"stargazers_count":7,"watchers_count":7,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":7,"mirror_url":null,"open_issues_count":11,"forks":7,"open_issues":11,"watchers":7,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/maxeler/maxpower/pulls/43"},"html":{"href":"https://github.com/maxeler/maxpower/pull/43"},"issue":{"href":"https://api.github.com/repos/maxeler/maxpower/issues/43"},"comments":{"href":"https://api.github.com/repos/maxeler/maxpower/issues/43/comments"},"review_comments":{"href":"https://api.github.com/repos/maxeler/maxpower/pulls/43/comments"},"review_comment":{"href":"https://api.github.com/repos/maxeler/maxpower/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/maxeler/maxpower/pulls/43/commits"},"statuses":{"href":"https://api.github.com/repos/maxeler/maxpower/statuses/37d68c017bb060339234a9ce567489cf320b8db5"}}}}