Skip to main content

TDT4160 1.1.3

tdt4160 is an emulator for IJVM-microinstructions and pseudo-assembly, as is commonly seen in the NTNU subject TDT4160, particularly on its exams.

There are two main components to this package. tdt4160.assembly and tdt4160.ijvm. Both function by letting you set registries, memory addresses and queue instructions before executing them. During execution, each individual instruction is stepped through, with lots of information printed so you can easily see what's going on. Technically requires Python >= 3.7 to be conformant, but should probably work with any version >= 3.6. There are no external dependencies besides the standard library.

View on PyPI | Fork me on gitgud

Installation

To install tdt4160, run:

$ python3 -m pip install tdt4160

or to install from source:

$ python3 setup.py install

Introduction

Due to COVID-19, most NTNU classes switched from exams in exam halls with no external help/tools allowed to home exams with all tools allowed. I thought it would be pretty funny if you could just automate the exams now that you're allowed to use tools.

I was right, it was pretty funny.

Example usage

Pseudo-assembly

# This example from the Autumn 2020 exam, task 6

from tdt4160.assembly import *

# First set the registries as specified in the task
set_asm_registries(
    R0=0xFFFF0000,
    R7=0xFFFF0001,
    R8=0xFFFF0002,
    R9=0xFFFF0003,
)

# Then set the memory addresses as specified
set_asm_addresses({
    0xFFFF0000: 0x00000001,
    0xFFFF0001: 0x00000002,
    0xFFFF0002: 0x00000003,
    0xFFFF0003: 0x00000004,
    0xFFFF0004: 0xFFFF0005
})

# Queue all the instructions to be performed
assemble(0x0000FFFE, LOAD, R8, R0)
assemble(0x0000FFFF, MOVC, R7, 1)
assemble(0x00010000, ADD, R0, R0, R7)
assemble(0x00010001, LOAD, R9, R0)
assemble(0x00010002, MUL, R9, R8, R9)
assemble(0x00010003, ADD, R9, R9, R8)
assemble(0x00010004, ADD, R0, R0, R7)
assemble(0x00010005, LOAD, R8, R0)
assemble(0x00010006, ADD, R8, R9, R8)

# Then actually run them
execute_assembly(0x0000FFFE)

# This function prints all the registries used in the task
# In this case, we're looking for R8, which is 6
print_asm_regs()

This outputs the following:

=============================== MEMORY: 0000FFFE ===============================
INSTRUCTION: LOAD R8=FFFF0002, R0=FFFF0000
Loaded value 00000001 into R8 from address FFFF0000
=============================== MEMORY: 0000FFFF ===============================
INSTRUCTION: MOVC R7=FFFF0001, Constant=00000001
Moved value 00000001 into R7
=============================== MEMORY: 00010000 ===============================
INSTRUCTION: ADD R0=FFFF0000, R0=FFFF0000, R7=00000001
Added R0=FFFF0000+R7=00000001
Result FFFF0001 stored in R0
=============================== MEMORY: 00010001 ===============================
INSTRUCTION: LOAD R9=FFFF0003, R0=FFFF0001
Loaded value 00000002 into R9 from address FFFF0001
=============================== MEMORY: 00010002 ===============================
INSTRUCTION: MUL R9=00000002, R8=00000001, R9=00000002
Multiplied R8=00000001*R9=00000002
Result 00000002 stored in R9
=============================== MEMORY: 00010003 ===============================
INSTRUCTION: ADD R9=00000002, R9=00000002, R8=00000001
Added R9=00000002+R8=00000001
Result 00000003 stored in R9
=============================== MEMORY: 00010004 ===============================
INSTRUCTION: ADD R0=FFFF0001, R0=FFFF0001, R7=00000001
Added R0=FFFF0001+R7=00000001
Result FFFF0002 stored in R0
=============================== MEMORY: 00010005 ===============================
INSTRUCTION: LOAD R8=00000001, R0=FFFF0002
Loaded value 00000003 into R8 from address FFFF0002
=============================== MEMORY: 00010006 ===============================
INSTRUCTION: ADD R8=00000003, R9=00000003, R8=00000003
Added R9=00000003+R8=00000003
Result 00000006 stored in R8
================================================================================
R0  = 0xFFFF0002
R7  = 0x00000001
R8  = 0x00000006
R9  = 0x00000003

IJVM

# This example from the Autumn 2020 exam, task 4

from tdt4160.ijvm import *

# Set the registries as specified
set_ijvm_registries(
    SP=0x10101010,
    LV=0x30000000,
    CPP=0x10000001,
    TOS=0xFF000000,
    OPC=0xABCDE000,
    H=0x12345678,
    MAR=0xA5A5A5A5,
    MDR=0x5A5A5A5A,
    PC=0x55AA55AA
)

# Queue the microinstructions to run
ijvm(0b000001000, 0b000001001, 0b000, 0b00010000, 0b100000000, 0b000, 0b1111)
ijvm(0b000001001, 0b000001011, 0b000, 0b00111001, 0b100000000, 0b000, 0b1100)
ijvm(0b000001010, 0b000010000, 0b001, 0b01011000, 0b010101010, 0b000, 0b0001)
ijvm(0b000001011, 0b000001100, 0b000, 0b00111100, 0b100000000, 0b000, 0b0101)
ijvm(0b000001100, 0b000000000, 0b000, 0b00111100, 0b000010000, 0b000, 0b0101)
ijvm(0b000001101, 0b000001110, 0b000, 0b00110010, 0b001000101, 0b100, 0b1000)

# Actually run them
execute_ijvm(0b000001000)

# Print the value of all the registries after execution
# In this case, we're looking for several registries, so just check the ones you want
print_all_ijvm()

This outputs the following:

======================= Instruction address: 0x000001000 =======================
next=0b000001001 JAM=0b000 ALU=0b00010000 C=0b100000000 Mem=0b000 B=0b1111
ALU is 0b010000, function: 0
Result of operation: 0x00000000
Final result: 0x00000000
C is 0b100000000
The following registries take the value of 0x00000000
H
Mem is 0b000
Mem is 0, don't touch memory
Next instruction: 0b000001001
======================= Instruction address: 0x000001001 =======================
next=0b000001011 JAM=0b000 ALU=0b00111001 C=0b100000000 Mem=0b000 B=0b1100
ALU is 0b111001, function: A + 1
A is always H=0x00000000
Result of operation: 0x00000001
Final result: 0x00000001
C is 0b100000000
The following registries take the value of 0x00000001
H
Mem is 0b000
Mem is 0, don't touch memory
Next instruction: 0b000001011
======================= Instruction address: 0x000001011 =======================
next=0b000001100 JAM=0b000 ALU=0b00111100 C=0b100000000 Mem=0b000 B=0b0101
ALU is 0b111100, function: A + B
A is always H=0x00000001
B is 0b0101 (5), yielding LV=0x30000000
Result of operation: 0x30000001
Final result: 0x30000001
C is 0b100000000
The following registries take the value of 0x30000001
H
Mem is 0b000
Mem is 0, don't touch memory
Next instruction: 0b000001100
======================= Instruction address: 0x000001100 =======================
next=0b000000000 JAM=0b000 ALU=0b00111100 C=0b000010000 Mem=0b000 B=0b0101
ALU is 0b111100, function: A + B
A is always H=0x30000001
B is 0b0101 (5), yielding LV=0x30000000
Result of operation: 0x60000001
Final result: 0x60000001
C is 0b000010000
The following registries take the value of 0x60000001
LV
Mem is 0b000
Mem is 0, don't touch memory
Next instruction: 0b000000000
================================================================================
Next instruction is 0. We're done
SP = 0x10101010
LV = 0x60000001
CPP = 0x10000001
TOS = 0xFF000000
OPC = 0xABCDE000
H = 0x30000001
MAR = 0xA5A5A5A5
MDR = 0x5A5A5A5A
PC = 0x55AA55AA
MBR = 0xUNINITIALIZED
MBRU = 0xUNINITIALIZED
MPC = 0x00000000

Note the uninitialized values were never touched, so they remain uninitialized. That's okay as long as we don't use them after.

På Norsk

tdt4160 er en emulator for IJVM-mikronstruksjoner og pseudo-assemblykode, som den man ofte ser i NTNU faget TDT4160 sine eksamener.

Det er to hoveddeler i pakkken. tdt4160.assembly og tdt4160.ijvm. Begge lar deg sette opp registre, minneaddresser, og sette instruksjoner i kø, før de blir utført. Mens instruksjonene kjører printes det masse informasjon ut om hva som faktisk utføres, slik at det blir lettere å se hva som skjer. Pakken krever teknisk sett en Pythonversjon som er >= 3.7, men bør fungere fint med alt >= 3.6. Pakken har ingen andre avhengigheter enn standardbiblioteket.

Se på PyPI | Gafle meg på gitgud

Installering

For å installere tdt4160, kjør:

$ python3 -m pip install tdt4160

eller for å installere fra kildekode:

$ python3 setup.py install

Introduksjon

Pga. COVID-19 har de fleste fag på NTNU byttet fra eksamen i eksamenshaller uten hjelpemidler til hjemmeeksamener med alle hjelpemidler tillat. Jeg syntes det hadde vært litt morsomt hvis man bare hadde noe verktøy som gjorde hele eksamenen for deg, nå som du kan bruke det du vil.

Hadde rett, det var ganske morsomt.

Eksempel

Pseudo-assembly

# Dette eksempelet er fra Høsteksamen 2020, oppgave 6

from tdt4160.assembly import *

# Først, sett opp alle registre som det står i oppgaven
set_asm_registries(
    R0=0xFFFF0000,
    R7=0xFFFF0001,
    R8=0xFFFF0002,
    R9=0xFFFF0003,
)

# Så sett opp alle minneaddresser
set_asm_addresses({
    0xFFFF0000: 0x00000001,
    0xFFFF0001: 0x00000002,
    0xFFFF0002: 0x00000003,
    0xFFFF0003: 0x00000004,
    0xFFFF0004: 0xFFFF0005
})

# Legg alle instruksjonene i kø for utførsel
assemble(0x0000FFFE, LOAD, R8, R0)
assemble(0x0000FFFF, MOVC, R7, 1)
assemble(0x00010000, ADD, R0, R0, R7)
assemble(0x00010001, LOAD, R9, R0)
assemble(0x00010002, MUL, R9, R8, R9)
assemble(0x00010003, ADD, R9, R9, R8)
assemble(0x00010004, ADD, R0, R0, R7)
assemble(0x00010005, LOAD, R8, R0)
assemble(0x00010006, ADD, R8, R9, R8)

# Kjør instruksjonene
execute_assembly(0x0000FFFE)


# Denne funksjonen printer alle registre som ble brukt i utførselen
# I dette tilfellet ser vi etter R8, som bør være 6
print_asm_regs()

Koden spytter ut følgende:

=============================== MEMORY: 0000FFFE ===============================
INSTRUCTION: LOAD R8=FFFF0002, R0=FFFF0000
Loaded value 00000001 into R8 from address FFFF0000
=============================== MEMORY: 0000FFFF ===============================
INSTRUCTION: MOVC R7=FFFF0001, Constant=00000001
Moved value 00000001 into R7
=============================== MEMORY: 00010000 ===============================
INSTRUCTION: ADD R0=FFFF0000, R0=FFFF0000, R7=00000001
Added R0=FFFF0000+R7=00000001
Result FFFF0001 stored in R0
=============================== MEMORY: 00010001 ===============================
INSTRUCTION: LOAD R9=FFFF0003, R0=FFFF0001
Loaded value 00000002 into R9 from address FFFF0001
=============================== MEMORY: 00010002 ===============================
INSTRUCTION: MUL R9=00000002, R8=00000001, R9=00000002
Multiplied R8=00000001*R9=00000002
Result 00000002 stored in R9
=============================== MEMORY: 00010003 ===============================
INSTRUCTION: ADD R9=00000002, R9=00000002, R8=00000001
Added R9=00000002+R8=00000001
Result 00000003 stored in R9
=============================== MEMORY: 00010004 ===============================
INSTRUCTION: ADD R0=FFFF0001, R0=FFFF0001, R7=00000001
Added R0=FFFF0001+R7=00000001
Result FFFF0002 stored in R0
=============================== MEMORY: 00010005 ===============================
INSTRUCTION: LOAD R8=00000001, R0=FFFF0002
Loaded value 00000003 into R8 from address FFFF0002
=============================== MEMORY: 00010006 ===============================
INSTRUCTION: ADD R8=00000003, R9=00000003, R8=00000003
Added R9=00000003+R8=00000003
Result 00000006 stored in R8
================================================================================
R0  = 0xFFFF0002
R7  = 0x00000001
R8  = 0x00000006
R9  = 0x00000003

IJVM

# Dette eksempelet er fra Høsteksamen 2020, oppgave 4

from tdt4160.ijvm import *

# Sett opp registre som det står i oppgaven
set_ijvm_registries(
    SP=0x10101010,
    LV=0x30000000,
    CPP=0x10000001,
    TOS=0xFF000000,
    OPC=0xABCDE000,
    H=0x12345678,
    MAR=0xA5A5A5A5,
    MDR=0x5A5A5A5A,
    PC=0x55AA55AA
)

# Skriv inn alle mikronstruksjonene
ijvm(0b000001000, 0b000001001, 0b000, 0b00010000, 0b100000000, 0b000, 0b1111)
ijvm(0b000001001, 0b000001011, 0b000, 0b00111001, 0b100000000, 0b000, 0b1100)
ijvm(0b000001010, 0b000010000, 0b001, 0b01011000, 0b010101010, 0b000, 0b0001)
ijvm(0b000001011, 0b000001100, 0b000, 0b00111100, 0b100000000, 0b000, 0b0101)
ijvm(0b000001100, 0b000000000, 0b000, 0b00111100, 0b000010000, 0b000, 0b0101)
ijvm(0b000001101, 0b000001110, 0b000, 0b00110010, 0b001000101, 0b100, 0b1000)

# Kjør instruksjonene
execute_ijvm(0b000001000)

# Skriv ut verdien til alle registrene etter at programmet har kjørt
# I dette tilfellet ser vi etter flere registre, plukk ut de du vil
print_all_ijvm()

Denne koden gir:

======================= Instruction address: 0x000001000 =======================
next=0b000001001 JAM=0b000 ALU=0b00010000 C=0b100000000 Mem=0b000 B=0b1111
ALU is 0b010000, function: 0
Result of operation: 0x00000000
Final result: 0x00000000
C is 0b100000000
The following registries take the value of 0x00000000
H
Mem is 0b000
Mem is 0, don't touch memory
Next instruction: 0b000001001
======================= Instruction address: 0x000001001 =======================
next=0b000001011 JAM=0b000 ALU=0b00111001 C=0b100000000 Mem=0b000 B=0b1100
ALU is 0b111001, function: A + 1
A is always H=0x00000000
Result of operation: 0x00000001
Final result: 0x00000001
C is 0b100000000
The following registries take the value of 0x00000001
H
Mem is 0b000
Mem is 0, don't touch memory
Next instruction: 0b000001011
======================= Instruction address: 0x000001011 =======================
next=0b000001100 JAM=0b000 ALU=0b00111100 C=0b100000000 Mem=0b000 B=0b0101
ALU is 0b111100, function: A + B
A is always H=0x00000001
B is 0b0101 (5), yielding LV=0x30000000
Result of operation: 0x30000001
Final result: 0x30000001
C is 0b100000000
The following registries take the value of 0x30000001
H
Mem is 0b000
Mem is 0, don't touch memory
Next instruction: 0b000001100
======================= Instruction address: 0x000001100 =======================
next=0b000000000 JAM=0b000 ALU=0b00111100 C=0b000010000 Mem=0b000 B=0b0101
ALU is 0b111100, function: A + B
A is always H=0x30000001
B is 0b0101 (5), yielding LV=0x30000000
Result of operation: 0x60000001
Final result: 0x60000001
C is 0b000010000
The following registries take the value of 0x60000001
LV
Mem is 0b000
Mem is 0, don't touch memory
Next instruction: 0b000000000
================================================================================
Next instruction is 0. We're done
SP = 0x10101010
LV = 0x60000001
CPP = 0x10000001
TOS = 0xFF000000
OPC = 0xABCDE000
H = 0x30000001
MAR = 0xA5A5A5A5
MDR = 0x5A5A5A5A
PC = 0x55AA55AA
MBR = 0xUNINITIALIZED
MBRU = 0xUNINITIALIZED
MPC = 0x00000000

Merk at to av registrene aldri ble satt, verken i oppsettet eller i koden, så de er bare UNINITIALIZED. Det er greit så lenge de aldri brukes til noe.

Metadata

Release files for tdt4160 1.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tdt4160 1.1.3
File Size Uploaded Provenance
tdt4160-1.1.3.tar.gz 17.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for tdt4160 1.1.3
File Interpreter ABI Platform
tdt4160-1.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 44.5 kB

Release files / tdt4160-1.1.3.tar.gz

Download URL tdt4160-1.1.3.tar.gz
Size 17.8 kB
Tags Source
SHA-256 checksum
How to use checksums
29ae85c50a7f509b89ce46e61e07dbcf27b7bbc89f729876b9d5f2b1abe9844b
BLAKE2b-256 checksum
How to use checksums
9ecb8873966f22d72a42ef8382b7d5530aad84fd1c4660293ba6fedec6165019
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.54.0 CPython/3.9.0

Release files / tdt4160-1.1.3-py3-none-any.whl

Download URL tdt4160-1.1.3-py3-none-any.whl
Size 26.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1295042c57267097f41c0ede6bbccec1020e90d946c9fdbdd3c0dd930cfe2552
BLAKE2b-256 checksum
How to use checksums
168f37616e53410330c821287199c6f8095164cdffaaab8d76ed96d51ef3d763
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.54.0 CPython/3.9.0

Security for tdt4160 1.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page