Compare commits

..

2 Commits

Author SHA1 Message Date
stupidcomputer 2d64d09f24 remove some vestigial packaging stuf; redo this later 2024-06-16 19:11:23 -05:00
stupidcomputer ee93c4db4c add more tests for the ISA; ISA bugfix
added more tests to the ISA -- covers all the instructions except RST
(reset).

fixed a bug in the ISA -- when comparing two numbers, we really compared
their pointers. in C, it's the difference between

```
int a = 10;
int b = 12;

int *ap = &a;
int *bp = &b;

if (ap < bp) { /* do stuff */ }
```

the problem is that you're comparing the pointers, *not* the values they
refer to. it instead should be like

if (*ap < *bp) { /* do stuff */ }

because you need to *dereference* the value before comparing. that's
what happens in cli/data/computer.py now.
2024-06-16 19:05:58 -05:00
6 changed files with 61 additions and 137 deletions

View File

@ -1,14 +1,15 @@
# desmos-computer # desmos-computer
## What is this? ## What is this?
- a client-server architecture for synchronizing a file containing Desmos expressions to a graph, (`cli/lib/server.py` and `cli/lib/clientside.py`) - a client-server architecture for synchronizing a file containing Desmos expressions to a graph,
- an instruction set architecture for Turing machines whose cells contain IEEE 754 compliant integers in each cell, (`cli/data/computer.py`) - a test suite for evaluating the 'correctness' of Desmos expressions,
- an assembler for that instruction set architecture, (not yet!) - an instruction set architecture for Turing machines whose cells contain IEEE 754 compliant integers in each cell,
- and other utilities. (disassembler, etc.) - an assembler for that instruction set architecture,
- and other utilities.
## How does the ISA work? ## How does the ISA work?
The 'CPU', implemented in Desmos, takes in a list (aka an array, Turing tape, etc.) and starts execution at cell 1 (lists have 1-based indexes in Desmos). The 'CPU', implemented in Desmos, takes in a list (aka an array, Turing tape, etc.) and starts execution at cell 1 (lists have 1-based indexes in Desmos).
The list also serves as the memory, as well. (Think like Befunge's `p` command.) The list also serves as the memory, as well. (Think like Befunge's `p` command.
*Todo: disconnect opcode definitions and opcodes from the actual CPU implementation. Because of this, don't rely on this table! Check the implementation in `data/computer.desmos`.* *Todo: disconnect opcode definitions and opcodes from the actual CPU implementation. Because of this, don't rely on this table! Check the implementation in `data/computer.desmos`.*
@ -42,21 +43,12 @@ Things we're optimizing for:
In general: *embed the intelligence into the machine code, **not** the CPU/ISA!* In general: *embed the intelligence into the machine code, **not** the CPU/ISA!*
## Things to do ## Things to do
- [x] Write a test suite for the various instruction of the ISA executing *in Desmos* - [ ] Write a test suite for evaluating arbitrary Desmos expressions and getting their expected outputs.
- [ ] Write an assembler to compile a custom Assembly language to native Desmos list format. - [ ] Write an assembler to compile a custom Assembly language to native Desmos list format.
- [ ] Simplify all this into a command line tool. - [ ] Simplify all this into a command line tool.
- [x] Simplify the synchronization stack. - [ ] Simplify the synchronization stack.
- [ ] Write documentation for all of this. - [ ] Write documentation for all of this.
## Running tests
- Enter the nix-shell, then start a web browser.
- Navigate to `https://desmos.com/calculator`, and open the dev console
- Run `python3 -m cli sync -c` to copy the userscript to your clipboard
- Run the userscript in the console
- Run `python3 -m unittest ./cli/tests/isa.py`, or other test groups if needed
- Keep the Desmos tab focused, as it may impede the ISA testing process
## License ## License
This project is licensed under the AGPLv3. See the `LICENSE` file for more information. This project is licensed under the AGPLv3. See the `LICENSE` file for more information.

View File

@ -2,86 +2,29 @@ from .lib.server import DesmosGraphServer
from .lib.graphparser import DesmosGraph, DesmosGraphOverride from .lib.graphparser import DesmosGraph, DesmosGraphOverride
from .lib.clientside import payload as JSGraphPayload from .lib.clientside import payload as JSGraphPayload
from .data.computer import payload as ComputerPayload from .tests.isa import test_entry_point
from .data.testing import payload as TestingPayload
import pyperclip
import argparse
def handle_sync(parser):
if parser.copy_userscript:
pyperclip.copy(JSGraphPayload)
print("copied userscript to clipboard")
if parser.filename:
graph = DesmosGraph.from_file(parser.filename)
if parser.override:
override = DesmosGraphOverride.from_file(parser.override)
graph.include_override(override)
server = DesmosGraphServer()
server.instructions_to_run = []
server.append_inst({
"type": "insert_graph",
"graph": graph,
})
server.start(no_stop=True)
def handle_data(parser):
if parser.dataname:
if parser.dataname == "computer.desmos":
print(ComputerPayload)
elif parser.dataname == "testing.desmos":
print(TestingPayload)
return
if parser.list:
parsers = ["computer.desmos", "testing.desmos"]
print('\n'.join(parsers))
def main(): def main():
parser = argparse.ArgumentParser( # graph = DesmosGraph.from_file("data/computer.desmos")
prog="desmosisa", # override = DesmosGraphOverride.from_file("test.override")
description="a smörgåsbord of utilities for desmos, including some implementations of an desmos-based isa", #
) # graph.include_override(override)
subparsers = parser.add_subparsers(dest="subparser_name") # server = DesmosGraphServer()
sync_parser = subparsers.add_parser("sync", help="desmos calculator synchronization utilities") # server.append_inst({
sync_parser.add_argument( # "type": "insert_graph",
'filename', # "graph": graph,
nargs='?', # })
help="filename of DesmosExpressions to synchronize with client" # server.append_inst({
) # "type": "test_graph",
sync_parser.add_argument( # "graph": graph,
'-o', '--override', # "name": "test and assert addition",
help="filename of DesmosOverride file, to override certain expressions in the DesmosExpression file", # "expectedOutput": [1, 4, 6, 0, 0, 4],
action="store" # "expression": "B",
) # })
sync_parser.add_argument( # server.start()
'-c', '--copy-userscript', # print(server.outputs)
help="copy the userscript to the clipboard, to be pasted into the JS console within the calculator.", #
action="store_true" test_entry_point()
)
data_parser = subparsers.add_parser("data", help="access various prebuilt files")
data_parser.add_argument(
'dataname',
nargs='?',
help='name of the datafile requested'
)
data_parser.add_argument(
'-l', '--list',
help='list available datafiles',
action='store_true'
)
args = parser.parse_args()
if args.subparser_name == "sync":
handle_sync(args)
if args.subparser_name == "data":
handle_data(args)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -22,10 +22,10 @@ id testing : B = []
: idiv(a, b, t_o) = setlistval(t_o, odiv(B[a], B[b])) : idiv(a, b, t_o) = setlistval(t_o, odiv(B[a], B[b]))
: imul(a, b, t_o) = setlistval(t_o, omul(B[a], B[b])) : imul(a, b, t_o) = setlistval(t_o, omul(B[a], B[b]))
: icmp(a, b, z) = { \\ : icmp(a, b, z) = { \
B[a] = B[b] : equals -> 1 , \\ B[a] = B[b] : equals -> 1 , \
B[a] > B[b] : greater -> 1 , \\ B[a] > B[b] : greater -> 1 , \
B[a] < B[b] : less -> 1 \\ B[a] < B[b] : less -> 1 \
} }
: irst(a, b, c) = equals -> 0, greater -> 0, less -> 0 : irst(a, b, c) = equals -> 0, greater -> 0, less -> 0
: ield(addr, b) = setlistval(addr, equals) : ield(addr, b) = setlistval(addr, equals)
@ -63,26 +63,26 @@ id testing : B = []
: paramthree = 0 : paramthree = 0
# main execution flows # main execution flows
: load(addr) = jumped -> 0, inst -> B[addr], \\ : load(addr) = jumped -> 0, inst -> B[addr], \
paramone -> B[addr + 1], \\ paramone -> B[addr + 1], \
paramtwo -> B[addr + 2], \\ paramtwo -> B[addr + 2], \
paramthree -> B[addr + 3] paramthree -> B[addr + 3]
: exec = { \\ : exec = { \
inst = sto : isto(paramone, paramtwo), \\ inst = sto : isto(paramone, paramtwo), \
inst = mov : imov(paramone, paramtwo), \\ inst = mov : imov(paramone, paramtwo), \
inst = add : iadd(paramone, paramtwo, paramthree), \\ inst = add : iadd(paramone, paramtwo, paramthree), \
inst = cmp : icmp(paramone, paramtwo, paramthree), \\ inst = cmp : icmp(paramone, paramtwo, paramthree), \
inst = eld : ield(paramone, paramtwo), \\ inst = eld : ield(paramone, paramtwo), \
inst = gld : igld(paramone, paramtwo), \\ inst = gld : igld(paramone, paramtwo), \
inst = lld : illd(paramone, paramtwo), \\ inst = lld : illd(paramone, paramtwo), \
inst = jmp : ijmp(paramone, paramtwo, paramthree), \\ inst = jmp : ijmp(paramone, paramtwo, paramthree), \
inst = be : ibe(paramone, paramtwo, paramthree), \\ inst = be : ibe(paramone, paramtwo, paramthree), \
inst = bne : ibne(paramone, paramtwo, paramthree), \\ inst = bne : ibne(paramone, paramtwo, paramthree), \
inst = bg : ibg(paramone, paramtwo, paramthree), \\ inst = bg : ibg(paramone, paramtwo, paramthree), \
inst = bl : ibl(paramone, paramtwo, paramthree), \\ inst = bl : ibl(paramone, paramtwo, paramthree), \
inst = sub : isub(paramone, paramtwo, paramthree), \\ inst = sub : isub(paramone, paramtwo, paramthree), \
inst = mul : imul(paramone, paramtwo, paramthree), \\ inst = mul : imul(paramone, paramtwo, paramthree), \
inst = div : idiv(paramone, paramtwo, paramthree) \\ inst = div : idiv(paramone, paramtwo, paramthree) \
} }
: incip = {jumped = 0 : ip -> ip + instwidth[inst] + 1} : incip = {jumped = 0 : ip -> ip + instwidth[inst] + 1}

View File

@ -4,5 +4,5 @@ payload = """
: m = 3 : m = 3
: y = m * x + b : y = m * x + b
: y = 2m * x + b : y = 2m * x + b
: \\frac{x^{2+3}}{3}*4*testing : \frac{x^{2+3}}{3}*4*testing
""" """

View File

@ -11,8 +11,6 @@ function arraysEqual(a, b) {
return true; return true;
} }
var refresh = true;
function main() { function main() {
let socket = new WebSocket("ws://localhost:8764"); let socket = new WebSocket("ws://localhost:8764");
var toCompare = ""; var toCompare = "";
@ -23,11 +21,9 @@ function main() {
} }
socket.onclose = function(e) { socket.onclose = function(e) {
if (refresh) { setTimeout(function() {
setTimeout(function() { main();
main(); }, 1000);
}, 1000);
}
} }
socket.onmessage = function(e) { socket.onmessage = function(e) {
@ -87,5 +83,5 @@ function main() {
console.log(`[LOG] couldn't parse message ${e.data}`) console.log(`[LOG] couldn't parse message ${e.data}`)
} }
} }
} } main();
""" """

View File

@ -89,25 +89,18 @@ class DesmosGraphServer:
} }
) )
if self.stop: self.stop.set_result("sotp please!!!!")
self.stop.set_result("sotp please!!!!")
async def main(self, stop): async def main(self, stop):
async with serve(self.ws_main, "localhost", 8764): async with serve(self.ws_main, "localhost", 8764):
self.stop = stop self.stop = stop
if not stop: await stop
await asyncio.Future()
else:
await stop
def start(self, no_stop=False): def start(self):
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
stop = loop.create_future() stop = loop.create_future()
if no_stop: loop.run_until_complete(self.main(stop))
loop.run_until_complete(self.main(stop=None))
else:
loop.run_until_complete(self.main(stop=stop))
def append_inst(self, inst): def append_inst(self, inst):
self.instructions_to_run.append(inst) self.instructions_to_run.append(inst)