Logisim Memory File generation using yo file

This section describes how to create logisim memory file out of .yo file. Let’s suppose we have Y86-64 SEQ processor implemented with the logisim tool. Then, how can you run test programs? In real computer system, we usually write a program with high level programming language such as C/C++ and compile it to make an executable file. Then, operating system loads the executable to the main memory and the processor starts program execution.

Since we focus on the processor design so we simplify the above processes.

1. Overall Steps

.ys --yas--> .yo --yo2mem--> .mem

Specifically, we rely on yas which is Y86-64 assembler. yas takes assembly code (.ys) as an input and outputs a memory file .yo that contains both machine code and data. However, Y86-64 SEQ implemented with logisim tool cannot directly understand yo file. Therefore, we are supposed to make a convertor from .yo to something that logisim can understand.

2. .yo file format

asum.yo
                              | # Execution begins at address 0
  0x000:                      |       .pos 0
  0x000: 30f40002000000000000 |       irmovq stack, %rsp      # Set up stack pointer
  0x00a: 803800000000000000   |       call main               # Execute main program
  0x013: 00                   |       halt                    # Terminate program
                              |
                              | # Array of 4 elements
  0x018:                      |       .align 8
  0x018: 0d000d000d000000     | array:        .quad 0x000d000d000d
  0x020: c000c000c0000000     |       .quad 0x00c000c000c0
  0x028: 000b000b000b0000     |       .quad 0x0b000b000b00
  0x030: 00a000a000a00000     |       .quad 0xa000a000a000
                              |
  0x038: 30f71800000000000000 | main: irmovq array,%rdi
  0x042: 30f60400000000000000 |       irmovq $4,%rsi
  0x04c: 805600000000000000   |       call sum                # sum(array, 4)
  0x055: 90                   |       ret
                              |
                              | # long sum(long *start, long count)
                              | # start in %rdi, count in %rsi
  0x056: 30f80800000000000000 | sum:  irmovq $8,%r8        # Constant 8
  0x060: 30f90100000000000000 |       irmovq $1,%r9        # Constant 1
  0x06a: 6300                 |       xorq %rax,%rax       # sum = 0
  0x06c: 6266                 |       andq %rsi,%rsi       # Set CC
  0x06e: 708700000000000000   |       jmp     test         # Goto test
  0x077: 50a70000000000000000 | loop: mrmovq (%rdi),%r10   # Get *start
  0x081: 60a0                 |       addq %r10,%rax       # Add to sum
  0x083: 6087                 |       addq %r8,%rdi        # start++
  0x085: 6196                 |       subq %r9,%rsi        # count--.  Set CC
  0x087: 747700000000000000   | test: jne    loop          # Stop when 0
  0x090: 90                   |       ret                  # Return
                              |
                              | # Stack starts here and grows to lower addresses
  0x200:                      |       .pos 0x200
  0x200:                      | stack:

`.yo file includes memmory contents followed by its corresponding assembly code in the input .ys file. In memory contents, it starts with start memory address followed by machine code or data. We just need memory contents for the logisim memory file.

3. Logisim Memory File

Logisim has its own file format that represents the content of memory. There are some versions of the memory file. If you are interested in logisim’s memory file format in detail, please refer to the logisim reference. In our term project, we are stick to use v3.0 hex words addressed.

4. YO2MEM pytyon script

 1  import sys
 2  import argparse
 3
 4  def parse(line):
 5      data = line.split('|')[0].strip()
 6      if ':' not in data:
 7          return None, None
 8
 9      addr = data.split(':')[0].strip()[2:]
10      data = data.split(':')[1].strip()
11
12      if len(data) == 0:
13          return None, None
14
15      assert(len(data) % 2 == 0)
16      num_bytes = int(len(data) / 2)
17
18      data_split = ''
19      for offset in range(num_bytes):
20          #print('offset: %d, idx: %d' % (offset, offset*2))
21          data_split += data[offset*2:offset*2+2] + ' '
22      return addr, data_split[:-1]
23
24  def add(memory, addr, data):
25      #assert(len(data) % 2 == 0)
26      addr = int(addr, 16)
27      memory[addr] = data
28
29  def translate(yo, mem):
30      #print("yo: %s, mem: %s" % (yo, mem))
31      memory = []
32      with open(yo, 'r') as f:
33          for line in f:
34              addr, data = parse(line)
35              if addr is not None:
36                  #print('addr: %s data: %s(%d)' % (addr, data, len(data)))
37                  memory.append((addr, data))
38
39      f = open(mem, 'w')
40      f.write('v3.0 hex words addressed\n')
41      for addr, data in memory:
42          f.write('%s: %s\n' % (addr, data))
43      f.close()
44      print("Translated %s file to memory file logisim-evolution. Find %s." % (yo, mem))
45
46  def main():
47      parser = argparse.ArgumentParser(
48              prog="yo2mem",
49              description="y86-64 object file to logisim-evolution memory file translator",
50              formatter_class=argparse.ArgumentDefaultsHelpFormatter
51      )
52      parser.set_defaults(func=lambda x: parser.print_help())
53      parser.add_argument('yo', action='store', type=str, help="input yo file")
54      parser.add_argument('mem', action='store', type=str, help="output memory file")
55
56      args = parser.parse_args(sys.argv[1:])
57      translate(args.yo, args.mem)
58
59  if __name__ == "__main__":
60      sys.exit(main())

This pythone script take two command line arguments as follows:

❯ python yo2mem -h
usage: yo2mem [-h] yo mem

y86-64 object file to logisim-evolution memory file translator

positional arguments:
  yo          input yo file
  mem         output memory file

optional arguments:
  -h, --help  show this help message and exit

The generated memory file will be used for both instruction and data memory.

v3.0 hex words addressed
000: 30 f4 00 02 00 00 00 00 00 00
00a: 80 38 00 00 00 00 00 00 00
013: 00
018: 0d 00 0d 00 0d 00 00 00
020: c0 00 c0 00 c0 00 00 00
028: 00 0b 00 0b 00 0b 00 00
030: 00 a0 00 a0 00 a0 00 00
038: 30 f7 18 00 00 00 00 00 00 00
042: 30 f6 04 00 00 00 00 00 00 00
04c: 80 56 00 00 00 00 00 00 00
055: 90
056: 30 f8 08 00 00 00 00 00 00 00
060: 30 f9 01 00 00 00 00 00 00 00
06a: 63 00
06c: 62 66
06e: 70 87 00 00 00 00 00 00 00
077: 50 a7 00 00 00 00 00 00 00 00
081: 60 a0
083: 60 87
085: 61 96
087: 74 77 00 00 00 00 00 00 00
090: 90