{"id":15398520,"url":"https://github.com/zero9178/minecraft-scientific-calculator","last_synced_at":"2026-01-03T17:05:14.833Z","repository":{"id":188026286,"uuid":"282863743","full_name":"zero9178/Minecraft-Scientific-Calculator","owner":"zero9178","description":"Scientific Calculator calculating with Half Precision Floating Point Numbers","archived":false,"fork":false,"pushed_at":"2021-01-26T10:42:22.000Z","size":9669,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-23T18:49:30.052Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zero9178.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-07-27T10:25:14.000Z","updated_at":"2021-03-29T19:50:29.000Z","dependencies_parsed_at":"2023-08-13T11:26:03.285Z","dependency_job_id":null,"html_url":"https://github.com/zero9178/Minecraft-Scientific-Calculator","commit_stats":null,"previous_names":["zero9178/minecraft-scientific-calculator"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zero9178%2FMinecraft-Scientific-Calculator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zero9178%2FMinecraft-Scientific-Calculator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zero9178%2FMinecraft-Scientific-Calculator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zero9178%2FMinecraft-Scientific-Calculator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zero9178","download_url":"https://codeload.github.com/zero9178/Minecraft-Scientific-Calculator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244006394,"owners_count":20382443,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T15:44:25.953Z","updated_at":"2026-01-03T17:05:09.803Z","avatar_url":"https://github.com/zero9178.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Scientific Calculator in Minecraft\n\n## Content\n\n1. [Introduction](#introduction)\n2. [Block Diagram](#block-diagram)\n3. [Redstone basics](#redstone-basics)\n4. [Memory architecture](#memory-architecture)\n5. [Instruction Set Architecture](#instruction-set-architecture)\n    1. [FPU Opcodes](#fpu-opcodes)\n    2. [ALU Opcodes](#alu-opcodes)\n    3. [Flags](#flags)\n6. [Assembly Program](#assembly-program)\n7. [Conclusion](#conclusion)\n\n## Introduction\n\nThis document describes some architectural decisions I made as well as concepts I implemented in my Scientific\nCalculator I built in Minecraft. I built this Calculator back in 2016/17 when I was 15 and published a video of it on\nYouTube on May 1st 2017. It's a nice and short summary and can be viewed\nhere: https://www.youtube.com/watch?v=3Gtik9eMeMU\u0026feature=emb_logo\n\n![Whole calculator](Calculator.png)\n![cosine operation](Cosine.png)\n![exponential function](Exponential.png)\n\nThe calculator is capable of doing following operations:\n\n* Add, Subtract\n* Multiply, Divide\n* Power Of, Square root\n* Natural logarithm, Base 10 logarithm\n* Exponential Function, root to base N\n* sine, cosine and tangent\n\nIt operates on real numbers and has a precision of 3 digits. The largest absolute number representable is 65504 and the\nsmallest around 0.00006. Add, Subtract, Multiple, Divide and Square root are simple operations that take around 2\nminutes to finish. Other operations take roughly 30 to 50 minute to finish. All input and output is done using\nScientific notation.\n\n## Block Diagram\n\n![Block diagram of the calculator](./Blockdiagram.png)\n\nThe whole Calculator can be split into three parts.\n\nThe largest and most important component is the FPU. It operates on IEEE 754 Half Precision Floating Point Numbers and\nsupports operations such as multiply, divide, add, subtract, square root and miscellaneous math functions like absolute.\nInstead of using registers, the FPU operates on a stack of eight numbers.\n\nThe ALU is a simple 8 bit ALU that has two register banks with registers R1 to R7 to work with. R0 is always the\nconstant 0. The ALUs main job in the calculator is implementing control flow like loops.\n\nLast is the Control Unit. It is responsible for taking in the 32 bit machine code, decoding it and then signaling all\ncomponents what to do. This includes what operations the FPU and ALU should be doing, which registers and stack slots\nshould be read or written to as well as controlling the program counter and return stack.\n\nThe whole CPU is single stage. During a single clock cycle the operand is decoded, memory read, operations performed and\nthen written back into memory. A single clock cycle takes 30s resulting in a frequency of 33.3 mHz. The ISA is 32 bit\nand capable of addressing both the FPU and ALU at the same time, allowing them to operate in parallel.\n\n## Redstone basics\n\nRedstone in Minecraft is a type of block able to carry digital. It can be turned on and off in an instance and has a\nrange of 15 blocks. After 15 blocks a so-called repeater must be placed to replenish the signal strength. A repeater\nalso adds a delay of 0.1 seconds to the signal. For Redstone to be turing complete a so called Redstone torch is used as\nan inverter. It is turned on by default and if the block the torch is placed on is powered by a Redstone signal the\ntorch turns off. Therefore, all digital circuits can be implemented in Minecraft. A torch acts as an inverter,\nconnecting two Redstone signals acts as an OR gate and using NOR Logic we can then implement an AND gate too.\n\n## Memory architecture\n\nFour different blocks of memory exist in the calculator.\n\nThe FPU operates on a stack of eight values that are all stored in 16 bit floating-point format. The instructions as\nwell as the stack architecture have largely been copied from the Intel 8087 Co processor. The first value in the stack\ncalled ST0 is the slot that new values are pushed onto or popped from. When doing an operation with the FPU, ST0 is\nalways one of the two operands or the only one. Results are either written to ST0 or the other operand depending on the\ninstruction. Instructions may also pop or push the stack.\n\nThe ALU operates on 7 registers R1 to R7. The instructions for the ALU are all three operand instructions. One is\ntherefore capable of choosing both operand registers, and the destination register. Registers R1 and R3 are actual 8 bit\nregisters. R4 to R7 are in reality 16 bit registers that store their values as 16 bit floating-point numbers. When read\nfrom or written to from the ALU conversion to 8-bit integer happens automatically. These 4 registers are also able to be\nread from or written to from the FPU and allows for interoperability between the two.\n\nThe largest block of memory is the ROM. It contains 1024 lines of 32 bit instructions where the whole calculator program\nis encoded into as machine code. It gets the address that should be read from directly from the program counter.\n\nInside the control unit there is also a program stack that can contain up to 4 addresses. It is used to jump into\nsubprograms and be able to return from them.\n\n## Instruction set architecture\n\nThe instruction set is 32 bits can capable of addressing FPU and ALU in parallel. It has 4 different layouts dependent\non the OP codes specified for both FPU and ALU.\n\n![Instruction Set Architecture of the Calculator](./ISA.png)\n\n### FPU Opcodes\n\nThe FPU OP Code is 5 bit allowing for a maximum of 32 operations. Unless the FI layout is used the next 3 bits STn is\nthe other operand of an operation. Operations may also push or pop values from the stack.\n\nIf the bit after STn is set, the roles of ST0 and STn are switched. As an example: If the FADDP OP Code is encountered\nST1 is specified in the STn field, and the bit is set then STn + ST0 is computed, the result stored into STn and then\nthe stack popped. Without the bit set, ST0 + STn would be computed, stored into ST0 and ST0 popped (which would be\nnonsensical). In Mnemonic the former would be written as `FADDP ST1;ST0`, the latter as `FADDP ST0;ST1`, roughly\nmirroring a 2 register operation scheme from ISAs like x86.\n\nFollowing FPU OP Codes exist:\n\n| Assembly name | OP-Code in binary | Description        | ISA Layout used if applicable |\n| ------------- | ----------------- | ------------------ | ----------------------------- |\n| FWAIT         | 00000             | No-op              | N/A                           |\n| FADD          | 00001             | ST0 = ST0 + STn          | N/A                           |\n| FADDP         | 00010             | ST0 = ST0 + STn, Pops    | N/A                           |\n| FSUB          | 00011             | ST0 = ST0 - STn          | N/A                           |\n| FSUBP         | 00100             | ST0 = ST0 - STn, Pops    | N/A                           |\n| FSUBR         | 00101             | STn = ST0 - STn   | N/A                           |\n| FSUBRP        | 00110             | STn = ST0 - STn, Pops   | N/A                           |\n| FMUL          | 00111             | ST0 = ST0 * STn          | N/A                           |\n| FMULP         | 01000             | ST0 = ST0 * STn, Pops    | N/A                           |\n| FDIV          | 01001             | ST0 = ST0 / STn          | N/A                           |\n| FDIVP         | 01010             | ST0 = ST0 / STn, Pops    | N/A                           |\n| FDIVR         | 01011             | STn = ST0 / STn,    | N/A                   |\n| FDIVRP        | 01100             | STn = ST0 / STn, Pops    | N/A                   |\n| FSQRT         | 01101             | ST0 = sqrt(ST0) | N/A                           |\n| FABS          | 01110             | ST0 = abs(ST0)    | N/A                           |\n| FSCALE        | 01111             | ST0 = 1 \u003c\u003c int(STO)  | N/A                           |\n| FEXP          | 10000             | ST0 = Floating point exponent of ST0  | N/A                           |\n| FMANT         | 10001             | ST0 = Floating point mantissa of ST0  | N/A                           |\n| FINT          | 10010             | ST0 = int(ST0)  | N/A                           |\n| FCOM          | 10011             | ST0 = ST0 - int(ST0)| N/A                           |\n| FEXM          | 10100             | Sets flags for ST0 | N/A                           |\n| FLOAD         | 10101             | Push value from Rn | N/A                           |\n| FSTORE        | 10110             | Pop ST0 into Rn    | N/A                           |\n| FCLOAD        | 10111             | Pushes math constant Cn | N/A                           |\n| FILOAD        | 11000             | Pushes immediate value | FI                           |\n| FBLD          | 11001             | Pushes number N from display | N/A                           |\n| FBSTP         | 11010             | Pop ST0 to display | N/A                           |\n\nThe `FCLOAD` instruction pushes a common math constant onto the FPU stack. Depending on the STn field, following math\nconstants are loaded:\n\n| STn Value | Constant |\n| --------|----------|\n| 0       | 0        |\n| 1       | 1        |\n| 2       | Pi       |\n| 3       | ln of 10 |\n| 4       | log2 of e|\n| 5       | log10 of 2|\n| 6       | ln of 2  |\n| 7       | e        |\n\n### ALU Opcodes\n\nDepending on the ALU instruction one of the three layouts RRR, RRI or JA are used. Most instructions use the RRR layout.\nIt's a RISC typical 3 register instruction layouts which saves into first specified destination register and uses the\nlatter 2 registers as left and right operands. The RRI layout is used with instructions that use a constant as the\nsecond operand. For both conditional and unconditional branches the JA layout is used to specify the target address.\n\nFollowing ALU Opcodes exist:\n\n| Assembly name | OP-Code in binary | Description        | ISA Layout used if applicable |\n| ------------- | ----------------- | ------------------ | ----------------------------- |\n| WAIT          | 000000            | No-op              | N/A                           |\n| ADD           | 000001            | Des = OP1 + OP2    | RRR                           |\n| ADC           | 000010            | Des = OP1 + OP2 + 1| RRR                           |\n| SUB           | 000011            | Des = OP1 - OP2    | RRR                           |\n| SBC           | 000100            | Des = OP1 - OP2 - 1| RRR                           |\n| OR            | 000101            | Des = OP1 OR OP2   | RRR                           |\n| AND           | 000110            | Des = OP1 AND OP2  | RRR                           |\n| XOR           | 000111            | Des = OP1 XOR OP2  | RRR                           |\n| NOT           | 001000            | Des = NOT OP1      | RRR                           |\n| SHR           | 001001            | Des = OP1 /2       | RRR                           |\n| SHL           | 001010            | Des = OP1 * 2      | RRR                           |\n| ADDI          | 001011            | Des = OP1 + I      | RRI                           |\n| ANDI          | 001100            | Des = OP1 AND I    | RRI                           |\n| BEQ           | 001101            | Jump if EQ set     | JA                            |\n| BNE           | 001110            | Jump if EQ not set | JA                            |\n| BMI           | 001111            | Jump if N set      | JA                            |\n| BPL           | 010000            | Jump if N not  set | JA                            |\n| BCS           | 010001            | Jump if C set      | JA                            |\n| BCC           | 010010            | Jump if C not set  | JA                            |\n| BLO           | 010011            | Jump if L set      | JA                            |\n| BLS           | 010100            | Jump if L or EQ set| JA                            |\n| BHS           | 010101            | Jump if H or EQ set| JA                            |\n| BHI           | 010110            | Jump if H set      | JA                            |\n| BLT           | 010110            | Jump if LE set     | JA                            |\n| BLE           | 010111            | Jump if LE or EQ set| JA                            |\n| BGE           | 011000            | Jump if G or EQ set| JA                            |\n| BGT           | 011001            | Jump if G set      | JA                            |\n| FBEZ          | 011011            | Jump if F0 set     | JA                            |\n| FBNZ          | 011100            | Jump if F0 not set | JA                            |\n| FBMI          | 011101            | Jump if FN set     | JA                            |\n| FBPL          | 011110            | Jump if FN not set | JA                            |\n| JMP           | 011111            | Unconditional Jump | JA                            |\n| JALS          | 100000            | Jump and push current Program Counter + 1 to Address Stack | JA                           |\n| RET           | 100001            | Jump to the top address on the address stack and pop it off the stack | N/A                            |\n| END           | 100010            | Set Program counter to 0 and halt | N/A                            |\n\n### Flags\n\nAll conditional branches jump depend on if a specific flag in the flag register is set. The values in the flag register\nare updated when the very last bit in the machine code is set. It will then examine the outputs and inputs of both the\nALU and the FPU for that specific instruction and update all flags in the flag register accordingly.\n\nFollowing flags are available:\n\n| Flag | Condition |\n| ---- | --------- |\n| EQ   | OP1 == OP2|\n| N    | ALU Result is negative |\n| C    | Carry Overflow in the ALU |\n| L    | unsigned OP1 \u003c OP2 |\n| H    | unsigned OP1 \u003e OP2 |\n| LE   | signed OP1 \u003c OP2 |\n| G    | signed OP1 \u003e OP2 |\n| F0   | FPU Result is 0  |\n| FN   | FPU Result is negative |\n\nOP1 and OP2 are either the two source registers or a register and the constant in the RRI layout.\n\n## Assembly program\n\nAs previously mentioned, more complicated operations such as calculating the sine of a number were implemented using\nalgorithms written in machine code. During development the program was first written down in Mnemonic to easily be able\nto edit and reason about the code. Only later and during debugging would I translate them manually into machine code and\nwrite them into the ROM of the Minecraft Calculator.\n\nEach line consisted of both an FPU instruction, and an ALU instruction as these are both executed in parallel (except\nfor the FILOAD instruction). To signify that an instruction should save it's generated flags into the flag register I\nused a `°` symbol at the end of the line. Operands in instructions are separated by `;`. Line comments started with `#`.\n\nAs a small example, here's the program for calculating the natural logarithm of a number in ST0 using a taylor series:\n\n```\n46    FCLOAD 0\t\tADDI R4;R0;3\t\t\t\t#Logarithm\n47    FADD ST0;ST1\tADDI R1;R0;2\n48    FEXP\t\t\tADDI R2;R0;9\n49    FSTORE R5\t\tWAIT\n50    FMANT\t\t\tWAIT\n51    FCLOAD 1\t\tWAIT\n52    FADD ST0;ST1\tWAIT\n53    FCLOAD 1\t\tWAIT\n54    FSUBP ST2;ST0\tWAIT\n55    FDIVP ST1;ST0\tWAIT\n56    FCLOAD 0\t\tWAIT\n57    FADD ST0;ST1\tWAIT\n58    FCLOAD 1\t\tWAIT\n59    FMUL ST0;ST2\tWAIT\n60    FMUL ST0;ST0\tWAIT\n61    FMUL ST2;ST0\tWAIT\n62    FLOAD R4\t\tADD R4;R4;R1\n63    FDIVR ST3;ST0\tOR R0;R4;R2\t\t°\n64    FADDP ST2;ST0\tBNE 61\n65    FSTORE 0\t\tWAIT\n66    FADD ST0;ST0\tWAIT\n67    FCLOAD 6\t\tWAIT\n68    FLOAD R5\t\tWAIT\n69    FMULP ST1;ST0\tWAIT\n70    FADDP ST1;ST0\tRET\n```\n\nLine numbers on the left were added here for correctness and are not part of the actual assembly code.\n\nThe full listing of the calculators program can be viewed [here](assembly.txt)\n\n## Conclusion\n\nIt's been roughly 3 years now since I finished this project. In those 3 years, while focused a lot more on programming,\nI learned a lot more about Computer Science in general and there are many things I would do differently today than back\nthen. The thing I am most proud of is probably the Instruction Set Architecture. While it being 32 Bit makes it\nrelatively enormous compared to the 8 bit and 16 bit the ALU and FPU operate on, allowing FPU and ALU instructions to\noperate parallel turned out quite useful.\n\nThings I would change in a second iteration of the CPU would be:\n\n* Pipelining:\n  The CPUs speed is currently massively bottlenecked by just a few operations. In particular Floating Point Division\n  takes ages compared to any other operation. Pipelining the whole CPU would by far be one of the most effective\n  optimizations and would be one of the most fun and complicated to implement as well.\n* Better circuits:\n  Pretty much all adders in the Calculator, including in the multiply and division circuits, are Ripple Carry Adders. I\n  am not sure if it would be feasible in Minecraft to use CLA adders and relatives due to space constraints, but it\n  would definitely yield massive improvements\n* Better flag handling:\n  In hindsight I feel like it is very awkward and unnecessary to set a bit at the end of a machine code instruction to\n  save flags to a flag register. Today I would probably make the flags be updated each instruction and make sure that\n  instructions only update specific flags that make sense instead of all of them.\n\nThere is also a bit more space for more instructions in the ALU, but I simply implemented those that I needed at the\ntime. \n\nI am hoping that one day I will once again find the time to get back into Micro architectures and CPUs and be able to\nimplement a spiritual successor to this calculator on an FPGA. ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzero9178%2Fminecraft-scientific-calculator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzero9178%2Fminecraft-scientific-calculator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzero9178%2Fminecraft-scientific-calculator/lists"}