Skip to main content

A CPU framework

Project description

Hello!
Have you ever tried to make a cpu simulation but don't want to write 300+ lines of code?
Well then you don't have to anymore!
AngelCPU does most of the heavy lifting for you, so let's get started before I fall asleep while typing this.

Getting Started

First lets install Angel

pip install angel-cpu

Now, let's start with some simple stuff, give me a second i'm setting up

from angel_cpu import *
ARCH=cpu("ARCH")

Alright now i'm done setting up. As you can see we have a class here

from angel_cpu import *
ARCH=cpu("ARCH")#THIS RIGHT HERE

Let's first set up the basic CPU ARCH

from angel_cpu import *
ARCH=cpu("ARCH")
# no reset does NOT reset the ARCH's registers and ram it just resets the ARCH's PC and Program
ARCH.reset()
# The name of the Register doesn't matter go crazy if you want
# The amount of Registers also don't matter, you can add like 50 of them and it wouldn't care
ARCH.add_register("Rxa")
ARCH.add_register("Rxb")
ARCH.add_register("Rxc")
ARCH.add_register("Rxe")
# the size is calculated by the x (400) times the y (200)
ARCH.add_ram(400,200)
# 32 bit integer limit
ARCH.set_max(0xffffffff)
# we're setting the command symbol to be ; so it's like real ASM
ARCH.set_comment_symbol(";")

huff that took me 30 minutes to write... (all of the time was because of the comments XD)
Anyway... let's go over what the eclipse is all of these before my head explodes

ARCH.reset()

Resets the ARCH's PC and Program

ARCH.add_register("Register name")

adds a register

ARCH.add_ram(400,200)

set's the ram size which with this one will be... give me a sec i'm calculating... 80000 cells... WOW

ARCH.set_max(0xffffffff)

sets the integer limit, I just put the 32 bit limit because it's the bare minimum trust me with this, you are going to need much more than 4294967295 bits trust me

ARCH.set_comment_symbol(";")

This Sets the comment symbol, any line that starts with it will be ignored in the assembler.\

Now that we got that covered it's time to add some opcodes so we can actually do stuff

from angel_cpu import *
ARCH=cpu("ARCH")
# no reset does NOT reset the ARCH's registers and ram it just resets the ARCH's PC and Program
ARCH.reset()
# The name of the Register doesn't matter go crazy if you want
# The amount of Registers also don't matter, you can add like 50 of them and it wouldn't care
ARCH.add_register("Rxa")
ARCH.add_register("Rxb")
ARCH.add_register("Rxc")
ARCH.add_register("Rxe")
# the size is calculated by the x (400) times the y (200)
ARCH.add_ram(400,200)
# 32 bit integer limit
ARCH.set_max(0xffffffff)
# we're setting the command symbol to be ; so it's like real ASM
ARCH.set_comment_symbol(";")
def MOV(reg,value):
    ARCH.set_register(reg,value)
def LOG(txt):
    if txt in ARCH.registers:
        print(ARCH.registers[txt])
    else:
        print(txt)
# It's important to note that when adding opcodes don't put parentheses on the function
# ARCH.add_opcode(0x0,MOV()) <-- incorrect, paratheses arnt opposed to be in the opcodes 
# ARCH.add_opcode(0x0,MOV) <-- correct
ARCH.add_opcode(0x0,MOV)
ARCH.add_opcode(0x1,LOG)
c="""
MOV Rxa 10
LOG Rxa
"""
ARCH.assemble(c)
ARCH.run()

Okay there's a lot of stuff here so let's talk about the things that changed

ARCH.add_opcode(hex_ID function)

This adds an opcode, and when adding the function, please, do not add parentheses

ARCH.assemble(code)

This assembles the code from ASM format into something that the CPU can actually understand, then it loads it into the CPU's program ready to run.

ARCH.run()

This takes the code from the Program and runs it, simple and very useful.

Now let's talk about the ASM format

MOV Rxa 10
LOG Rxa

The command comes first, each argument comes after the command separated by spaces, but then you might be wondering, "what about strings with spaces in them?" well, strings are strings so there has to be these (") surrounding them, without that it wouldn't be a string!

Alright this is taking a long time so i'll just boot something give me a sec...

[BIOS]: BOOTING CMD DUMP...

[BIOS]: INIT REG

[REG]: [OK]

[BIOS]: INIT SD

[SD]: [OK]

[BOOTING ASM_HELPER]: [OK]

[ASM_HELPER]: [OK]

Alright, I booted ASM_helper to speed things along, here's the rest of the commands along with some stuff I already covered

add_register: adds a register, there's not much to say about this, but registers can be named anything, however their value cannot go over the integer limit, we'll go over how to set that in a bit

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.add_register("register")

add_ram: sets the ram, the size is calulated by the X times the Y however the RAM is a 1D plane, so you can just use get_ram(addr) with the addr being an int

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.add_ram("size_x","size_y")

add_opcode: adds an opcode for a function, please note that commands must be inputted without parentheses or you RISC (haha get it?) making the commands have set arguments

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.add_opcode("opcode","commmand")

add_instruction: This is for those of you who want to make your own assembler, or those of you who just want to add instructions without the assembler

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.add_instruction("opcode")

set_window_name: This sets the Window's name, and as a side note the window's name starts as the arch's name, but you can set this to what ever you want

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.set_window_name("name")

set_max: sets the integer limit, it can be any type of int, like hex, and i recomend using hex because it's much easier to write large numbers in hex, for example 0xffffffff in decimal is 4294967295, now you see what i mean?

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.set_max("number")

set_pc: sets the PC, for those of you who aren't fluent in tech, PC means program counter, it tells the CPU what instruction it's meant to be looking at, and it's very useful with making commands like JMP

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.set_pc("number")

set_register: sets a register's value, however if the register's value overflows to more than the integer limit the register's value resets back to it's base, depending on the type of data the register was holding the fallback will be different, for example if it was holding a string, and the string's length was longer than the max interger limit it falls back to an empty string ("") the same is for lists, dicts, tuples, and ints, with ints having a fallback of 0x0

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.set_register("register","value")

set_ram: sets a ram cell's value, if the value is larger than the integer limit it will fall back to empty, with lists,dicts, and tuples they will fallback to and empty version of themselves with ints falling back to 0x0

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.set_ram("address","value")

reset: resets the PC and the program of the CPU, with the PC resetting to 0x0 and the program resetting back to none

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.reset()

set_comment_symbol: sets the command symbol, if you where to set it to ; any line starting with ; would be commented out and ignored by the assembler

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.set_comment_symbol("symbol")

get_register: returns the value of the selected register, that's it.

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.get_register("register")

get_ram: gets the value of the selected ram cell, that's it

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.get_ram("address")

get_pc: returns the value of the PC of the CPU, that's it.

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.get_pc()

text: prints text onto the screen window, the text will not render until frame is called, the AddToTxtLog input must either be True or False, False means when you write text_input the text will not show up on the screen, while True means it will, the end input is what will be put on the end of the text, if end is not "\n" then it will not create a new line when drawing, the first input in the customy input must either be True or False, True means customy is enabled, if it is False then customy will not be enabled, the second input for customy is the y value, note that the y value will only be that if customy is enabled

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.text("text","x_pos",("color_R","color_G","color_B"),"Add_to_text_log","end",("Is customy enabled?","y_pos"))

wait: waits for the set amount of time, note that the time is in milliseconds.

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.wait(1000)

scroll: scrolls the screen by the set amount

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.scroll("X","Y")

is_Mouse_Touching_Surface: it returns True is the mouse if touching a surface, else, it returns False

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.is_Mouse_Touching_Surface("name")

show_mouse: it sets the mouse's visiblity, if true it shows the mouse, if false it doesn't else? it breaks, it must either be true or false

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.show_mouse("True, or False")

quit: when this command is called it quits the screen and the app, i recommend only using it when you need to close EVERYTHING

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.quit()

frame: displays the next frame on the screen window, that's it, it just displays the next frame

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.frame()

load_pixels: loads the pixels from the pixel buffer to the screen, it needs frame to display the changes to the screen

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.load_pixels()

events: events returns the events that happened with key presses it returns kDWN and then the key that's pressed so for e it would return kDWNe, for key release it will return kUP so releasing the key e would make it return kUPe, for mouse down it would return a tuple, with the first being mDWN and the second being another tuple containing the mouse X and Y, when the mouse is UP it returns mUP with the pos following

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.events()

clear: clears the screen buffer, the changes don't update until frame is called

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.clear()

clear_logs: clears the screen logs, this makes it useful with text_input because it stops trailing text

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.clear_logs()

is_held: it returns true if the inputted key is held down, else it returns false

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.is_held("key")

render_surfaces: This renders the surfaces, you have to call frame to see the effects though

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.render_surfaces()

add_surface: This adds a surface, you have to call render_furfaces and frame to see them

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.add_surface("name","width","height",("color_R","color_G","colo_rB"),"pos_X","pos_Y")

add_pixel: adds a pixel, you have to call load_pixels and frame to see the effects

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.add_pixel("pos_x","pos_y",("color_R","color_G","colo_rB"),"size","group","addtopixellog")

text_input: Text_input displays text on the screen as a prompt, then after the key enter is pressed, it returns what the user typed

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.text_input("prompt",("color_R","color_G","colo_rB"),"prompt_end","prompt_x")

mouse_down_on_group: This returns True if the mouse has clicked a pixel group

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.mouse_down_on_group("event output","group")

mouse_pos: returns the mouse pos in a tuple

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.mouse_pos()

assemble: one of the most useful commands in angel, it compiles your ASM code into opcodes so your CPU can run it, now it compiles ASM not the opcodes themselves so don't go inputting 0x0 for MOV or 0x1 for JMP that just won't work

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.assemble("code")

run: runs the code in the program, the program is set by using assemble

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.run()

0.7 commands: the following commands are the new commands added in angel-cpu 0.7

[SD]: LOADING 0.7 COMMANDS

[SD]: [OK]

add_disk: Adds a disk, add_disk returns a disk class, using this you can create disks and persisting storage, if you are trying to use the ARCH object with the disk use attach_device

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.add_disk("sector_size","sectors")

[SD]: found multiple entries in the Disk class, go over them as well?

uh... sure...

[SD]: Loading Disk sub commands...

write: writes to the inputted address, note that the address is a tuple, with the first input being the sector and the second being the cell

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.add_disk("sector_size","sectors")
x.write(("addr-sector","addr_cell"),"data")

read: reads from the inputted address, note that the address is a tuple, with the first input being the sector and the second being the cell

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.add_disk("sector_size","sectors")
x.read(("addr_sector","addr_cell"))

format: formats the Disk, returns the Disk back to when it was first defined

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.add_disk("sector_size","sectors")
x.format()

dump: dumps the disk, this dumps the disk to a file, the name input is the name of the file, so i recomend you select one name and stick with it

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.add_disk("sector_size","sectors")
x.dump("name")

load: loads the disk from the inputted file, note that the name must be exactly what the Disk's file name is

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.add_disk("sector_size","sectors")
x.load("name")

[SD]: Disk sub commands completed, returning back to CPU commands...

attach_device: attaches a device to the CPU, the devices can be anything, extra storage, disks, and if you wanted to, you could add an entire second CPU as an device, but i recommend you don't do that, it's hard to manage two CPUs a once,

from angel_cpu import *
ARCH=cpu("ARCH")
device=ARCH.add_disk("sector_size","sectors")
ARCH.attach_device("name",device)

get_device: returns the inputted device, this one returns the inputted device's class object, but like how not everything is a potato, not all devices are class based, so it returns whatever the device is

from angel_cpu import *
ARCH=cpu("ARCH")
x=ARCH.add_disk("sector_size","sectors")
ARCH.attach_device("disk",x)
div=ARCH.get_device("disk")

0.9 commands: the following commands are the new commands added in angel-cpu 0.9

[SD]: LOADING 0.9 COMMANDS

[SD]: [OK]

set_multiline_comment_symbol_start: sets the multiline comment symbol start, not much to say here just don't try to put comments in comments it doesn't work...

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.set_multiline_comment_symbol_start("<:")

set_multiline_comment_symbol_end: sets the multiline comment symbol end, not much to say here, just don't try to put comments in comments it doesn't work...

from angel_cpu import *
ARCH=cpu("ARCH")
ARCH.set_multiline_comment_symbol_end(":>")

And that's all for this update!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

angel_cpu-1.0.tar.gz (16.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

angel_cpu-1.0-py3-none-any.whl (11.6 kB view details)

Uploaded Python 3

File details

Details for the file angel_cpu-1.0.tar.gz.

File metadata

  • Download URL: angel_cpu-1.0.tar.gz
  • Upload date:
  • Size: 16.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for angel_cpu-1.0.tar.gz
Algorithm Hash digest
SHA256 39ff24c910d014caee89801d74f5e578c6b5e7fc8ab736c0fc29b95df1c6c191
MD5 433240f903a2cac044d21b93aef9a4c7
BLAKE2b-256 3f16a4cfb17fda9aab165c8c93647568c25608871b84002c5aacfa571fd77065

See more details on using hashes here.

File details

Details for the file angel_cpu-1.0-py3-none-any.whl.

File metadata

  • Download URL: angel_cpu-1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for angel_cpu-1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b3e5b735fbd961a513e3ad2bb1701f12167cafc43055a485d4149fe995cee951
MD5 51dee624e85eb379082d8750f578f4fe
BLAKE2b-256 d8d93767202a7c088074b9bc7adb20b8a56e9d710386062044e85ebfac4f6e30

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page