diff options
-rw-r--r-- | assets/ppu-level-1.svg | 3 | ||||
-rw-r--r-- | docs/ppu.drawio | 1 | ||||
-rw-r--r-- | docs/research.md | 144 |
3 files changed, 138 insertions, 10 deletions
diff --git a/assets/ppu-level-1.svg b/assets/ppu-level-1.svg new file mode 100644 index 0000000..f8592a2 --- /dev/null +++ b/assets/ppu-level-1.svg @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1434px" height="474px" viewBox="-0.5 -0.5 1434 474" style="background-color: rgb(255, 255, 255);"><defs/><g><rect x="531" y="81" width="480" height="390" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="3" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 92px; margin-left: 178px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Basys3 FPGA<br />PPU</div></div></div></foreignObject><text x="257" y="96" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Basys3 FPGA...</text></switch></g><rect x="1131" y="81" width="300" height="390" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="3" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 92px; margin-left: 378px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Display output<br />(VGA)</div></div></div></foreignObject><text x="427" y="96" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Display output...</text></switch></g><rect x="110.91" y="81" width="300.09" height="390" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="3" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 92px; margin-left: 38px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">STM32F091RC<br />CPU</div></div></div></foreignObject><text x="87" y="96" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">STM32F091RC...</text></switch></g><path d="M 412.5 357 L 412.5 345 L 501 345 L 499.5 345 L 499.5 328.5 L 529.5 351 L 499.5 373.5 L 499.5 357 L 501 357 Z" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="1.42" pointer-events="all"/><path d="M 499.5 345 L 499.5 328.5 L 529.5 351 L 499.5 373.5 L 499.5 357" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 117px; margin-left: 179px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">VRAM-ADDR</div></div></div></foreignObject><text x="179" y="120" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px">VRAM-ADDR</text></switch></g><path d="M 412.5 417 L 412.5 405 L 471 405 L 499.5 405 L 499.5 388.5 L 529.5 411 L 499.5 433.5 L 499.5 417 L 471 417 Z" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="1.42" pointer-events="all"/><path d="M 499.5 405 L 499.5 388.5 L 529.5 411 L 499.5 433.5 L 499.5 417" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 137px; margin-left: 179px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">VRAM-DATA</div></div></div></foreignObject><text x="179" y="140" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px">VRAM-DATA</text></switch></g><path d="M 1011 141 L 1041 141 L 1111.9 141" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.65 141 L 1106.65 151.5 L 1111.9 141 L 1106.65 130.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 47px; margin-left: 335px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">V-SYNC</div></div></div></foreignObject><text x="335" y="50" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="end">V-SYNC</text></switch></g><path d="M 1011 201 L 1071 201 L 1111.9 201" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.65 201 L 1106.65 211.5 L 1111.9 201 L 1106.65 190.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 67px; margin-left: 335px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">H-SYNC</div></div></div></foreignObject><text x="335" y="70" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="end">H-SYNC</text></switch></g><path d="M 1011 291 L 1041 291 L 1111.9 291" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.65 291 L 1106.65 301.5 L 1111.9 291 L 1106.65 280.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 97px; margin-left: 335px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">RED</div></div></div></foreignObject><text x="335" y="100" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="end">RED</text></switch></g><path d="M 1011 351 L 1041 351 L 1111.9 351" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.65 351 L 1106.65 361.5 L 1111.9 351 L 1106.65 340.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 117px; margin-left: 335px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">GREEN</div></div></div></foreignObject><text x="335" y="120" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="end">GREEN</text></switch></g><path d="M 1011 411 L 1041 411 L 1111.9 411" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.65 411 L 1106.65 421.5 L 1111.9 411 L 1106.65 400.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 137px; margin-left: 335px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">BLUE</div></div></div></foreignObject><text x="335" y="140" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="end">BLUE</text></switch></g><path d="M 411 141 L 501 141 L 511.9 141" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 527.65 141 L 506.65 151.5 L 511.9 141 L 506.65 130.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 47px; margin-left: 179px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">ENABLE</div></div></div></foreignObject><text x="179" y="50" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px">ENABLE</text></switch></g><path d="M 1011 141 L 1041 141 L 1041 51 L 51 51 L 51 141 L 91.81 141" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 107.56 141 L 86.56 151.5 L 91.81 141 L 86.56 130.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 47px; margin-left: 39px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">V-SYNC</div></div></div></foreignObject><text x="39" y="50" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px">V-SYNC</text></switch></g><path d="M 1011 201 L 1071 201 L 1071 21 L 21 21 L 21 201 L 91.81 201" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 107.56 201 L 86.56 211.5 L 91.81 201 L 86.56 190.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 67px; margin-left: 39px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">H-SYNC</div></div></div></foreignObject><text x="39" y="70" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px">H-SYNC</text></switch></g><path d="M 411 201 L 471 201 L 511.9 201" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 527.65 201 L 506.65 211.5 L 511.9 201 L 506.65 190.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(3)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 67px; margin-left: 179px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">RESET</div></div></div></foreignObject><text x="179" y="70" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px">RESET</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file diff --git a/docs/ppu.drawio b/docs/ppu.drawio new file mode 100644 index 0000000..17ea515 --- /dev/null +++ b/docs/ppu.drawio @@ -0,0 +1 @@ +<mxfile host="Electron" modified="2023-02-05T15:24:04.957Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.8.16 Chrome/106.0.5249.199 Electron/21.4.0 Safari/537.36" etag="Sw92OaPQb4kISNLgk6ge" version="20.8.16" type="device" pages="2"><diagram name="level-1" id="DBE48RpXtx8JnoEt3ekA">7Vpdb9owFP01SNsDVb6BxwApndQiBLRbH11iQjaDI8cU2K+f09iExEBIQwma6EMV31xfO8fnXPu6remd+bpHQDB7wi5ENU1x1zW9W9M0w2yx35FhExuaViM2eMR3Y5OaGEb+X8iNCrcufReGKUeKMaJ+kDZO8GIBJzRlA4TgVdptilF61AB4UDKMJgDJ1p++S2f8K0wlsT9A35uJkVWFv5kD4cwN4Qy4eLVj0p2a3iEY0/hpvu5AFGEncIn73R94u50YgQt6Sgdz84PSX3S8VMerV4T7lqM81HmUd4CW/IPbINyEOrPdD3p2TbMQC95+I+zJi54Gg2f+OXQjMCJ4uXBhNIzCPFYzn8JRACbR2xUjBbPN6Byxlsoe5WmLOUBC4XrHxD+jB/EcUrJhLuJtk0PKOaXz5ipZINXittnu4ghHwEnhbUMnuLEHDl0BGDUJxq4fBghEk8ZLGiypjOS3l579vXIs9ROwVC6KpS5hORo/6dq90lKHHRnGzhUQUm/dtRonwHin6JdEUm1IUL4M7ae63e0OJczgwrWjfMlaEwTC0J+kYUpjCl2WJXlnTOgMe3gBkJNY2xC9fQSLUPRZPmUmgHxvwUwITqOVYwkxiPpPEVzzodshJfjPNtNG47J58V1B/3gPCN1ps6YH6QASn0EGSbTK/sITC8/DGKLjNq4SB061D/IgxEsygfmMjeeSn2wj7E5KcxKFzD1CFDYCEaD+e3rb2kcpPt4A++w7k8GMgxwWQWIceL/djSYTSmtKoYxMKL5s2VCMBR8pU7gFkUN4ZNKNdPJSs1tgMX/2EM8g01tMB0+nIaS1rCy3K1dCqc39Su3aY/tKlVpMXMdVfJPeuaRnGtlQjS+SnilNWjVy1JfbpToBGrL+6qPXfkcWX66c0vJLfB4xDrhCf0NKN5z/YElxWr9CfCRmWgl1iIIpTx1aMXWIuMV4X5RhuplO1uZxdh13r45ZlsSshxuzKmaWlaZKI4dZR92rY5Z8Zhg63RutriZhibr51IyV8a+OWC2JWL2h4/Rv1LoeauUUOjn+FRY6isSt9uOzc6PW9VAr5xSf418dtTSZWk7fbj/uIdfFC+jPc+tW4GYKXClU64sKXEsaKacCye1RoTbkS/Xq69vS2jg17+qf0kZJ0hvqITYUJr0h/32hno11JtaXLLpzjiVaGe+r0ZJ8V1R9Rf+fa0mTBJC91iyjpexmdC4tlbtmUHN2mzLe13KFoe27wxg5Y1lKtyPbZY9spnKn7PyoKfpYnxSf2lKOxjnb0a2Q8I67f4U4WDP5v5/YPfnnKd35Bw==</diagram><diagram id="lj51MlK96fuJFRP7cw84" name="level-2">1Zhbs5owEMc/DY9nhouKPnrQY2tr6xw79bGTwgqpgTAxXj99FwkqBtueViu+OMk/t81vF5bVcLx4MxAkjUY8AGbYZrAxnJ5h241mB38zYZsL7ZabC6GgQS5ZR2FCd6BEU6lLGsCiNFFyziRNy6LPkwR8WdKIEHxdnjbjrHxqSkLQhIlPmK5OaSAjdYumedTfAQ2j4mTLVCMxKSYrYRGRgK9PJKdvOJ7gXOateOMBy9gVXPJ1LxdGD4YJSOSfLHhNv3/ytkP4xqMfg9FwKMzZ7snOd1kRtlQX9j5+UPbKbQFB8GUSQLaPaTjP64hKmKTEz0bX6HXUIhkz7FnY1O1Spq5ASNicSMrOAfAYpNjilE3Z+dtyd310QEdJ0Qn7widEuTw87Hukgg0F5g2QHA3S10E3I0TDhGSrQ0hAEMnF/cnVDF1DQ/dM/Hm4x7J/auOUL2gdyJ0HnXtnck2N3AsXUEdy5zF3b3ItjdyY+nIpIDssCOD+xOr2gnM1YpNUIATU8JZIrAbMahZkbT0nvHZH/0Ypg0Hx06PLMLGgJnl6HXbO38Wb5d6KXkdPC9eGF9MgyDa6Cj+7zK+h83Mr+Nm3wlf47zQ5PBK/1r35WRq/L5RBjEwehuGh0PgNxJs9w5ZeO4yxbJISy7WHodj+f5FoD6bcnXhi3vu8m9uyP6L91ZMeiNP3Yw0fXk6WGS2k4HPwOMPvP6eX8CTjM6OMnUlEMfQRGSbxX8CtckrZbRdYV3jkchI/D+KKN2mrgr/zdv7YPdbW+7GTPyic/k8=</diagram></mxfile>
\ No newline at end of file diff --git a/docs/research.md b/docs/research.md index 7eca454..1c13739 100644 --- a/docs/research.md +++ b/docs/research.md @@ -20,36 +20,160 @@ this chip's features and limitations: - composite output at 256x224 @ 60Hz (NTSC) or 256x240 @ 50Hz (PAL) - 256 tiles per tilemap (with 8x8 tiles) -- 2 tilemaps +- 2 tilemaps (pattern tables) - 4 palettes per sprite with 64 possible colors -- 512x480 background palette with scrolling +- 512x480 background canvas with scrolling - background scrolling splits -- 64 total sprites on screen (8 per scanline) +- 64 total sprites on screen (max 8 per scanline) - sprites can be drawn before or after the background layer - PPU control using DMA - 8K character memory (tilemaps) -- 2K nametable memory +- 2K nametable memory (OAM for background tiles) - 256B object attribute memory (OAM) - tiles can be flipped using OAM - no frame buffer +### Usage + +The NES PPU has a lot of capabilities, so here's a quick run-down of how the +PPU is used by games to produce pictures. + +On boot, the NES copies the contents of the so-called CHR-ROM (in game +cartridge) into the PPU's pattern tables. The NES has two 256-tile tilemaps +called the pattern tables which store all sprites in the game. By modifying the +nametable memory directly, the game can control which tile, and which palette +will be used for any given tile on the background layer. Because the background +layer only displays tiles in a fixed grid, the nametable memory area is not +very big. + +The same process happens for the foreground sprites, though these can each be +positioned using screen coordinates, and don't have to conform to any grid. The +NES also has some limitations on how many sprites can be drawn and how many +palettes can be used. An important note is that the first color of any palette +used on any foreground sprite, is treated as the transparency color. Our PPU +also copies this behavior. + +The following is a small section of pseudocode, depicting a program that will +display a triangle moving in a circle: + +```c +unsigned frame = 0; + +void setup() { + // copy character rom to PPU + memcpy(CHR, PPU->CHR, 0x8000); + // character rom contains a sprite of a triangle at index 0 + + // set palette index 0 to have 4 random colors + PAL[0] = (palette) { + PALETTE_COLOR_25, + PALETTE_COLOR_F3, + PALETTE_COLOR_00, + PALETTE_COLOR_3D, + }; + // copy palette data to PPU + memcpy(PAL, PPU->PAL, 0x40); +} + +void loop() { + frame++; // increment frame counter + + OAM[0] = (sprite) { + .x = sin(frame) * 20 + 10, // calculate circle position using frame counter + .y = cos(frame) * 20 + 10, // calculate circle position using frame counter + .pattern_index = 0, // triangle sprite + .palette_index = 0, // palette 0 (see setup) + .attributes = PPU_FX_FLIP_H | PPU_FX_FLIP_V, // flip horizontally and vertically + }; + + memcpy(OAM, PPU->OAM, 0x100); // update PPU with local copy of OAM +} + +int main() { + setup(); + while(1) loop(); +} +``` + ## Custom PPU Here's a list of features our PPU should have: <!-- TODO: expand list with PPU spreadsheet --> -- 256x240 @ 60Hz VGA output -- single tilemap with room for 2048 tiles of 8x8 pixels +- 256x224 @ 60Hz VGA output +- single tilemap with room for 1024 tiles of 16x16 pixels - 8 colors per palette, with 4096 possible colors (12-bit color depth) -- 512x480 background palette with scrolling -- **NO** background scrolling splits -- 128 total sprites on screen (**NO** scanline sprite limit) +- 512x448 background canvas with scrolling +- NO background scrolling splits +- 128 total sprites on screen (NO scanline sprite limit) - sprites are always drawn on top of the background layer - PPU control using DMA (dual-port asynchronous RAM) -- tiles can be flipped using OAM +- tiles can be flipped using FAM or BAM - no frame buffer - vertical and horizontal sync output +Notable differences: + +- NES nametable equivalent is called BAM (background attribute register) +- NES OAM equivalent is called FAM (foreground attribute register) +- No scanline sprite limit + + Unless not imposing any sprite limit makes the hardware implementation + impossible, or much more difficult, this is a restriction that will likely + lead to frustrating debugging sessions, so will not be replicated in our + custom PPU. +- Sprites are 16x16 + + Most NES games already tile multiple 8x8 tiles together into "metatiles" to + create the illusion of larger sprites. This was likely done to save on memory + costs as RAM was expensive in the '80s, but since we're running on an FPGA + cost is irrelevant. +- Single 1024 sprite tilemap shared between foreground and background sprites + + The NES OAM registers contain a bit to select which tilemap to use (of two), + which effectively expands each tile's index address by one byte. Instead of + creating the illusion of two separate memory areas for tiles, having one + large tilemap seems like a more sensible solution to indexed tiles. +- 8 total palettes, with 8 colors each + + More colors is better. Increasing the total palette count is a very memory + intensive operation, while increaing the palette color count is likely slower + when looking up color values for each pixel on real hardware. +- Sprites can be positioned paritally off-screen on all screen edges using only + the offset bits in the FAM register + + The NES has a separate PPUMASK register to control special color effects, and + to shift sprites off the left and top screen edges, as the sprite offsets + count from 0. Our PPU's FAM sprite offset bits count from -15, so the sprite + can shift past the top and left screen edges, as well as the standard bottom + and right edges. +- No status line register, only V-sync and H-sync outputs are supplied back to + CPU + + The NES status line register contains some handy lines, such as a buggy + status line for reaching the max sprite count per scanline, and a status line + for detecting collisions between background and foreground sprites. Our PPU + doesn't have a scanline limit, and all hitbox detection is done in software. + Software hacks involving swapping tiles during a screen draw cycle can still + be achieved by counting the V-sync and H-sync pulses using interrupts. +- No background scrolling splits + + This feature allows only part of the background canvas to be scrolled, while + another portion stays still. This was used to draw HUD elements on the + background layer for displaying things like health bars or score counters. + Since we are working with a higher foreground sprite limit, we'll use regular + foreground sprites to display HUD elements. +- Sprites are always drawn on top of the background layer + + Our game doesn't need this capability for any visual effects. Leaving this + feature out will lead to a simpler hardware design + +### Hardware design schematics + +![PPU top-level design](../assets/ppu-level-1.svg) + +![PPU level 2 design](../assets/ppu-level-2.svg) + [nesppuspecs]: https://www.copetti.org/writings/consoles/nes/ [nesppudocs]: https://www.nesdev.org/wiki/PPU_programmer_reference [nesppupinout]: https://www.nesdev.org/wiki/PPU_pinout |