#!/usr/bin/python3
#
# 
# Utility for the Single AXI4 memory mapped (MM) user interface of the The Xilinx DMA/Bridge Subsystem for PCI Express (pg195)
# Author: Ton Damen, tond@nikhef.nl
# Date: 3/9/2020
#

import os
import sys
import argparse

parser = argparse.ArgumentParser(description='Spec7 tool to access the memory mapped area', epilog='A number with prefix "0x" is interpreted as hex value')
parser.add_argument('--device', '-d', default='/dev/spec7_bar0', help = 'device path name, default is /dev/spec7')
parser.add_argument('--address', '-a', default='0', help='address to access (0x prefix for hex)')
parser.add_argument('--is-pipe', '-p', dest='is_pipe', action="store_true", help='register is a pipe')
parser.add_argument('--count', '-n', dest='count', help='number of reads/writes')
action_args = parser.add_mutually_exclusive_group()
action_args.add_argument('--write', '-w', metavar='value',nargs='+', help='write value(s) to address (0x prefix for hex)')
action_args.add_argument('--write-from-file', '-f', dest='write_file', help='write file to memory from address');
action_args.add_argument('--copy-to-file', dest='read_file', help='copy memory to file from address')


args = parser.parse_args()


def str2int(s):
	try:
		if (len(s) > 0 and s[0:2] == '0x'):
			val = int(s[2:], 16)
		else:
			val = int(s)
		return val
	except ValueError:
		sys.exit('Invalid value: {}'.format(s))
	

address = str2int(args.address)

if address & 3 != 0:
	sys.exit('Address not word aligned')

try:
	if args.read_file:
		file = open(args.read_file, 'wb')
	elif args.write_file:
		file = open(args.write_file, 'rb')
except OSError as error:
	sys.exit(error)

try:
	fd = os.open(args.device, os.O_RDWR)
	if args.write:
		for data in args.write:
			os.pwrite(fd, str2int(data).to_bytes(4, 'little'), address)
			address += 4
	elif args.write_file:
		while True:
			if args.count:
				if args.count == 0:
					break
				else:
					args.count -= 1

			data = file.read(4)	# file is big-endian byte order		
			if len(data) == 4:
				value = int.from_bytes(data, 'big')
				os.pwrite(fd, value.to_bytes(4, 'little'), address)
			else:
				break
			if not args.is_pipe:
				address += 4;

	elif args.read_file:
		if not args.count:
			sys.exit('Missing count option')
		n = int(args.count)
		while n > 0:
			data = os.pread(fd, 4, address)			
			file.write(int.from_bytes(data, 'little').to_bytes(4, 'big'))
			if not args.is_pipe:
				address += 4
			n -= 1
			
	else:
		data = os.pread(fd, 4, address)
		print ('{:08x}'.format((int.from_bytes(data, "little"))))
		
except OSError as error: 
	sys.exit('Device i/o failed: {}'.format(error))


if 'file' in globals():
	file.close()

