aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/ppu-level-1.svg3
-rw-r--r--docs/ppu.drawio1
-rw-r--r--docs/research.md144
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