campctf2023-chall-tis256

Zachtronics TIS100-inspired reversing challenge for CampCTF 2023
git clone https://git.sinitax.com/sinitax/campctf2023-chall-tis256
Log | Files | Refs | Submodules | README | sfeed.txt

bus.py (5372B)


      1import sys
      2
      3from tpu import *
      4
      5# connect up parts to a bus.. layouting not important
      6
      7# we designate X0 Y0 as the input port from the bus
      8# we designate X1 Y0 as the output port to the bus
      9
     10bus_upper_out_port = """
     11start:
     12    mov RIGHT, ACC
     13    jne {addr}, fwd
     14    mov {addr}, DOWN
     15    mov RIGHT, DOWN
     16    mov RIGHT, DOWN
     17    mov RIGHT, DOWN
     18    mov RIGHT, DOWN
     19    jmp start
     20fwd:
     21    mov ACC, LEFT
     22    mov RIGHT, LEFT
     23    mov RIGHT, LEFT
     24    mov RIGHT, LEFT
     25    mov RIGHT, LEFT
     26"""
     27
     28bus_lower_out_port = """
     29start:
     30    mov ANY, ACC
     31    jne {addr}, fwd
     32    mov ANY, DOWN
     33    mov ANY, DOWN
     34    mov ANY, DOWN
     35    mov ANY, DOWN
     36    jmp start
     37fwd:
     38    mov ACC, RIGHT
     39    mov LEFT, RIGHT
     40    mov LEFT, RIGHT
     41    mov LEFT, RIGHT
     42    mov LEFT, RIGHT
     43"""
     44
     45bus_lower_in_port = """
     46start:
     47    mov ANY, ACC
     48    sav
     49    mov ANY, ACC
     50    jne {addr}, fwd
     51    swp
     52    mov ACC, UP
     53    mov ACC, RIGHT
     54    mov {addr}, UP
     55    mov {addr}, RIGHT
     56    mov DOWN, ACC
     57    mov ACC, UP
     58    mov ACC, RIGHT
     59    mov DOWN, ACC
     60    mov ACC, UP
     61    mov ACC, RIGHT
     62    mov DOWN, ACC
     63    mov ACC, UP
     64    mov ACC, RIGHT
     65    jmp start
     66fwd:
     67    swp
     68    mov ACC, RIGHT
     69    swp
     70    mov ACC, RIGHT
     71    mov LEFT, RIGHT
     72    mov LEFT, RIGHT
     73    mov LEFT, RIGHT
     74"""
     75
     76bus_lower_rail = """
     77mov ANY, RIGHT
     78"""
     79
     80bus_upper_rail = """
     81mov ANY, LEFT
     82"""
     83
     84bus_rail_end = """
     85mov ANY, NIL
     86"""
     87
     88def does_collide(main, offx, part):
     89    for (x,y),_ in part["tpus"].items():
     90        if (x+offx,y) in main["tpus"]:
     91            return True
     92    dirs = {"UP": (0, -1), "RIGHT": (1, 0), "DOWN": (0, 1), "LEFT": (-1, 0)}
     93    for port in ("stdin", "stdout"):
     94        if port in part:
     95            x,y,d = part[port]
     96            dx,dy = dirs[d]
     97            if (x+offx+dx,y+dy) in main["tpus"]:
     98                return True
     99        if port in main:
    100            x,y,d = main[port]
    101            dx,dy = dirs[d]
    102            if (x+dx-offx,y+dy) in part["tpus"]:
    103                return True
    104    return False
    105
    106def add_part(main, main_maxx, bus_ports, part):
    107    portx = main_maxx
    108    while portx in bus_ports or portx+1 in bus_ports or does_collide(main, portx, part):
    109        portx += 1
    110    bus_ports[portx] = ("in", part["addr"])
    111    bus_ports[portx+1] = ("out", part["addr"])
    112    for (x,y),ls in part["tpus"].items():
    113        main["tpus"][(x+portx,y)] = ls
    114    if "stdin" in part:
    115        assert("stdin" not in main)
    116        x,y,d = part["stdin"]
    117        main["stdin"] = (portx+x,y,d)
    118    if "stdout" in part:
    119        assert("stdout" not in main)
    120        x,y,d = part["stdout"]
    121        main["stdout"] = (portx+x,y,d)
    122    return portx + 4
    123
    124def tolines(asm):
    125    return asm.strip("\n").split("\n")
    126
    127def apply(part, transforms):
    128    old_tpus = part["tpus"]
    129    part["tpus"] = TPUDict({})
    130    for (x,y),ls in old_tpus.items():
    131        nx = transforms[0](x, y)
    132        ny = transforms[1](x, y)
    133        part["tpus"][(nx,ny)] = ls
    134
    135def rotate(part, r90=0):
    136    dirs = ("UP", "RIGHT", "DOWN", "LEFT")
    137    transforms = (
    138        (lambda x,_: x, lambda _,y: y),
    139        (lambda _,y: -y, lambda x,_: x),
    140        (lambda x,_: -x, lambda _,y: -y),
    141        (lambda _,y: y, lambda x,_: -x),
    142    )
    143    apply(part, transforms[r90])
    144    for _,ls in part["tpus"].items():
    145        for li,l in enumerate(ls):
    146            for d in dirs:
    147                l = l.replace(d, d.upper())
    148            for i,d in enumerate(dirs):
    149                nd = dirs[(i+r90)%len(dirs)]
    150                l = l.replace(d, nd.lower())
    151            for d in dirs:
    152                l = l.replace(d.lower(), d)
    153            ls[li] = l
    154
    155def add_ports(main, bus_ports):
    156    for x,(dir,addr) in bus_ports.items():
    157        dir,addr = bus_ports[x]
    158        if dir == "in":
    159            main["tpus"][(x,-2)] = tolines(bus_upper_out_port.format(addr=addr))
    160            main["tpus"][(x,-1)] = tolines(bus_lower_out_port.format(addr=addr))
    161        else:
    162            main["tpus"][(x,-2)] = tolines(bus_upper_rail)
    163            main["tpus"][(x,-1)] = tolines(bus_lower_in_port.format(addr=addr))
    164
    165def add_rail(main, bus_ports):
    166    bus_start = min(bus_ports)
    167    bus_end = max(bus_ports) + 1
    168    for x in range(bus_start, bus_end + 1):
    169        if x not in bus_ports:
    170            main["tpus"][(x,-2)] = tolines(bus_upper_rail)
    171            main["tpus"][(x,-1)] = tolines(bus_lower_rail)
    172    main["tpus"][(bus_start-1,-1)] = tolines(bus_rail_end)
    173    main["tpus"][(bus_start-1,-2)] = tolines(bus_rail_end)
    174    main["tpus"][(bus_end+1,-1)] = tolines(bus_rail_end)
    175    main["tpus"][(bus_end+1,-2)] = tolines(bus_rail_end)
    176
    177if __name__ == "__main__":
    178    main = { "tpus": TPUDict({}) }
    179    files = sys.argv[2:]
    180    if "--" in files:
    181        split = files.index("--")
    182    else:
    183        split = None
    184
    185    bus_ports = {}
    186    main_maxx = 0
    187    for arg in files[:split]:
    188        main_maxx = add_part(main, main_maxx,
    189            bus_ports, parse(open(arg).read()))
    190    add_ports(main, bus_ports)
    191
    192    if split is not None:
    193        rotate(main, 2)
    194        apply(main, (lambda x,_: x, lambda _,y: y-3))
    195
    196        all_ports = {-k:v for k,v in bus_ports.items()}
    197        main_maxx = min(all_ports)
    198        for arg in files[split+1:]:
    199            main_maxx = add_part(main, main_maxx,
    200                all_ports, parse(open(arg).read()))
    201        add_ports(main, {k:v for k,v in all_ports.items() if -k not in bus_ports})
    202        add_rail(main, all_ports)
    203    else:
    204        add_rail(main, bus_ports)
    205
    206    write(main, sys.argv[1])