golang.org/x/arch@v0.17.0/s390x/s390xspec/spec.go (about)

     1  // Copyright 2024 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // S390xspec reads the Principles of Operation PDF Manual
     6  // to collect instruction encoding details and writes those details to standard output
     7  // in CSV format.
     8  //
     9  // Usage:
    10  //
    11  //	s390xspec z_Architecture_Principles_of_Operation.pdf > s390x.csv
    12  //
    13  // Each CSV line contains three fields:
    14  //
    15  //	instruction
    16  //		The instruction heading, such as "BRANCH AND LINK".
    17  //	mnemonic
    18  //		The instruction mnemonics, such as "BAL R1,D2(X2,B2)".
    19  //	encoding
    20  //		The instruction encoding, a sequence of opcode and operands encoding in respective bit positions
    21  //		such as operand@bitposition each separated by |
    22  //		Ex: "45@0|R1@8|X2@12|B2@16|D2@20|"
    23  //
    24  // For more on the exact meaning of these fields, see the Principle of Operations IBM-Z Architecture PDF Manual.
    25  package main
    26  
    27  import (
    28  	"bufio"
    29  	"fmt"
    30  	"log"
    31  	"math"
    32  	"os"
    33  	"sort"
    34  	"strconv"
    35  	"strings"
    36  
    37  	"rsc.io/pdf"
    38  )
    39  
    40  type Inst struct {
    41  	Name  string
    42  	Text  string
    43  	Enc   string
    44  	Flags string
    45  }
    46  
    47  var stdout *bufio.Writer
    48  
    49  func main() {
    50  	log.SetFlags(0)
    51  	log.SetPrefix("s390xspec: ")
    52  
    53  	if len(os.Args) != 2 {
    54  		fmt.Fprintf(os.Stderr, "usage: s390xspec file.pdf\n")
    55  		os.Exit(2)
    56  	}
    57  
    58  	f, err := pdf.Open(os.Args[1])
    59  	if err != nil {
    60  		log.Fatal(err)
    61  	}
    62  
    63  	// Split across multiple columns and pages!
    64  	var all = []Inst{}
    65  
    66  	// Scan document looking for instructions.
    67  	// Must find exactly the ones in the outline.
    68  	n := f.NumPage()
    69  	for pageNum := 1; pageNum <= n; pageNum++ {
    70  		page := f.Page(pageNum)
    71  		t1 := getPageContent(page)
    72  		if len(t1) > 0 && match(t1[0], "Helvetica-Bold", 13.98, "Instructions Arranged by Name") {
    73  			for n := pageNum; n < pageNum+24; n++ {
    74  				page := f.Page(n)
    75  				table := parsePage(n, page)
    76  				all = append(all, table...)
    77  			}
    78  			break
    79  		} else {
    80  			continue
    81  		}
    82  	}
    83  	stdout = bufio.NewWriter(os.Stdout)
    84  	for _, inst := range all {
    85  		if strings.Contains(inst.Name, "\x00I") {
    86  			r := rune(0x2190)
    87  			inst.Name = strings.Replace(inst.Name, "\x00I", string(r), -1)
    88  		} else if strings.Contains(inst.Name, "I\x00") {
    89  			r := rune(0x2192)
    90  			inst.Name = strings.Replace(inst.Name, "I\x00", string(r), -1)
    91  		}
    92  		fmt.Fprintf(stdout, "%q,%q,%q,%q\n", inst.Name, inst.Text, inst.Enc, inst.Flags)
    93  	}
    94  	stdout.Flush()
    95  
    96  }
    97  
    98  // getPageContent gets the page content of a single PDF page
    99  func getPageContent(p pdf.Page) []pdf.Text {
   100  	var text []pdf.Text
   101  
   102  	content := p.Content()
   103  	for _, t := range content.Text {
   104  		text = append(text, t)
   105  	}
   106  
   107  	text = findWords(text)
   108  	return text
   109  }
   110  
   111  // parsePage parses single PDF page and returns the instructions content
   112  func parsePage(num int, p pdf.Page) []Inst {
   113  	var insts []Inst
   114  	text := getPageContent(p)
   115  
   116  	for {
   117  		var heading, mnemonic, format string
   118  		// The float numbers below are the horizontal X-coordinate values to be parsed out of the Z-ISA PDF book.
   119  		for len(text) > 0 && !(match(text[0], "Helvetica-Narrow", 8, "") && (matchXCord(text[0], 73.9) || matchXCord(text[0], 55.9))) {
   120  			text = text[1:]
   121  		}
   122  		if len(text) == 0 {
   123  			break
   124  		}
   125  		heading = text[0].S
   126  		text = text[1:]
   127  		// The float numbers below are the horizontal X-coordinate values to be parsed out of the Z-ISA PDF book.
   128  		for !(matchXCord(text[0], 212.2) || matchXCord(text[0], 230.1) || matchXCord(text[0], 246.2) || matchXCord(text[0], 264.2)) {
   129  			heading += text[0].S
   130  			if match(text[0], "Wingdings3", 0, "") {
   131  				heading += text[1].S
   132  				text = text[1:]
   133  			}
   134  			text = text[1:]
   135  		}
   136  		if strings.Compare(heading, "DIAGNOSE") == 0 {
   137  			text = text[1:]
   138  			continue
   139  		}
   140  		heading, check, m := checkHeading(heading)
   141  		if check {
   142  			mnemonic = m
   143  		} else {
   144  			mnemonic = text[0].S
   145  			text = text[1:]
   146  		}
   147  		index := strings.Index(mnemonic, " ")
   148  		if index != -1 {
   149  			format = mnemonic[index+1:]
   150  			mnemonic = mnemonic[:index]
   151  		} else {
   152  			format = text[0].S
   153  		}
   154  		text = text[1:]
   155  		if strings.Compare(format, "SS") == 0 {
   156  			format += text[0].S
   157  		}
   158  		before, _, _ := strings.Cut(format, " ")
   159  		format = before
   160  		// The float numbers below are the horizontal X-coordinate values to be parsed out of the Z-ISA PDF book.
   161  		for len(text) > 0 && !(match(text[0], "Helvetica-Narrow", 8, "") && (matchXCord(text[0], 350.82) || matchXCord(text[0], 363.84) || matchXCord(text[0], 332.82) || matchXCord(text[0], 345.84))) {
   162  			if text[0].X > 405.48 {
   163  				break
   164  			}
   165  			text = text[1:]
   166  		}
   167  		flags := text[0].S
   168  		// The float numbers below are the horizontal X-coordinate values to be parsed out of the Z-ISA PDF book.
   169  		for len(text) > 0 && !(match(text[0], "Helvetica-Narrow", 8, "") && ((matchXCord(text[0], 481.7) && (!matchXCord(text[1], 496.1))) || matchXCord(text[0], 496.1) || (matchXCord(text[0], 499.6) && (!matchXCord(text[1], 514))) || (matchXCord(text[0], 514)))) {
   170  			text = text[1:]
   171  		}
   172  		if len(text) == 0 {
   173  			break
   174  		}
   175  		opcode := text[0].S
   176  		b1, b2, _ := strings.Cut(opcode, " ")
   177  		if matchXCord(text[0], 481.7) || matchXCord(text[0], 499.6) {
   178  			opcode = b2
   179  		} else {
   180  			opcode = b1
   181  		}
   182  		if strings.Compare(text[0].S, b1) == 0 {
   183  			text = text[2:]
   184  		} else {
   185  			text = text[1:]
   186  		}
   187  		mnemonic1, encoding := frameMnemonic(mnemonic, format, opcode)
   188  		for match(text[0], "Helvetica-Narrow", 5.1, "") {
   189  			text = text[1:]
   190  		}
   191  		if match(text[0], "Helvetica-Oblique", 9, "") {
   192  			text = text[2:]
   193  			insts = append(insts, Inst{heading, mnemonic1, encoding, flags})
   194  			continue
   195  		}
   196  		if strings.HasPrefix(text[0].S, "(") {
   197  			y123 := text[0].Y
   198  			for text[0].Y == y123 && !matchXCord(text[0], 5.1) {
   199  				heading += text[0].S
   200  				text = text[1:]
   201  			}
   202  		} else if !(math.Abs(text[0].Y-text[1].Y) < 0.3) {
   203  			heading += " " + text[0].S
   204  			text = text[1:]
   205  		}
   206  		insts = append(insts, Inst{heading, mnemonic1, encoding, flags})
   207  		if match(text[0], "Helvetica-Oblique", 9, "") {
   208  			break
   209  		}
   210  	}
   211  	return insts
   212  }
   213  
   214  func checkHeading(heading string) (string, bool, string) {
   215  	substr := []string{"ALSI", "ALGSI", "CHRL", "CGHRL", "CUXTR", "IEXTR", "RXSBG", "RISBLG", "VERIM", "VPSOP"}
   216  	b := false
   217  	for _, s := range substr {
   218  		r1 := strings.Index(heading, s)
   219  		if r1 != -1 {
   220  			heading = heading[:r1-1]
   221  			b = true
   222  			return heading, b, s
   223  		}
   224  	}
   225  	return heading, b, ""
   226  }
   227  
   228  func frameMnemonic(mnemonic, format, opcode string) (string, string) {
   229  
   230  	var mn, enc string
   231  
   232  	switch format {
   233  	case "E":
   234  		mn, enc = mnemonic_E(mnemonic, opcode)
   235  	case "I":
   236  		mn, enc = mnemonic_I(mnemonic, opcode)
   237  	case "IE":
   238  		mn, enc = mnemonic_IE(mnemonic, opcode)
   239  	case "MII":
   240  		mn, enc = mnemonic_MII(mnemonic, opcode)
   241  	case "RI-a", "RI-b", "RI-c":
   242  		mn, enc = mnemonic_RI(mnemonic, format, opcode)
   243  	case "RIE-a", "RIE-b", "RIE-c", "RIE-d", "RIE-e", "RIE-f", "RIE-g":
   244  		mn, enc = mnemonic_RIE(mnemonic, format, opcode)
   245  	case "RIL-a", "RIL-b", "RIL-c":
   246  		mn, enc = mnemonic_RIL(mnemonic, format, opcode)
   247  	case "RIS":
   248  		mn, enc = mnemonic_RIS(mnemonic, opcode)
   249  	case "RR":
   250  		mn, enc = mnemonic_RR(mnemonic, opcode)
   251  	case "RRD":
   252  		mn, enc = mnemonic_RRD(mnemonic, opcode)
   253  	case "RRE":
   254  		mn, enc = mnemonic_RRE(mnemonic, opcode)
   255  	case "RRF-a", "RRF-b", "RRF-c", "RRF-d", "RRF-e":
   256  		mn, enc = mnemonic_RRF(mnemonic, format, opcode)
   257  	case "RRS":
   258  		mn, enc = mnemonic_RRS(mnemonic, opcode)
   259  	case "RS-a", "RS-b":
   260  		mn, enc = mnemonic_RS(mnemonic, format, opcode)
   261  	case "RSI":
   262  		mn, enc = mnemonic_RSI(mnemonic, opcode)
   263  	case "RSL-a", "RSL-b":
   264  		mn, enc = mnemonic_RSL(mnemonic, format, opcode)
   265  	case "RSY-a", "RSY-b":
   266  		mn, enc = mnemonic_RSY(mnemonic, format, opcode)
   267  	case "RX-a", "RX-b":
   268  		mn, enc = mnemonic_RX(mnemonic, format, opcode)
   269  	case "RXE":
   270  		mn, enc = mnemonic_RXE(mnemonic, opcode)
   271  	case "RXF":
   272  		mn, enc = mnemonic_RXF(mnemonic, opcode)
   273  	case "RXY-a", "RXY-b":
   274  		mn, enc = mnemonic_RXY(mnemonic, format, opcode)
   275  	case "S":
   276  		mn, enc = mnemonic_S(mnemonic, opcode)
   277  	case "SI":
   278  		mn, enc = mnemonic_SI(mnemonic, opcode)
   279  	case "SIL":
   280  		mn, enc = mnemonic_SIL(mnemonic, opcode)
   281  	case "SIY":
   282  		mn, enc = mnemonic_SIY(mnemonic, opcode)
   283  	case "SMI":
   284  		mn, enc = mnemonic_SMI(mnemonic, opcode)
   285  	case "SS-a", "SS-b", "SS-c", "SS-d", "SS-e", "SS-f":
   286  		mn, enc = mnemonic_SS(mnemonic, format, opcode)
   287  	case "SSE":
   288  		mn, enc = mnemonic_SSE(mnemonic, opcode)
   289  	case "SSF":
   290  		mn, enc = mnemonic_SSF(mnemonic, opcode)
   291  	case "VRI-a", "VRI-b", "VRI-c", "VRI-d", "VRI-e", "VRI-f", "VRI-g", "VRI-h", "VRI-i":
   292  		mn, enc = mnemonic_VRI(mnemonic, format, opcode)
   293  	case "VRR-a", "VRR-b", "VRR-c", "VRR-d", "VRR-e", "VRR-f", "VRR-g", "VRR-h", "VRR-i", "VRR-j", "VRR-k":
   294  		mn, enc = mnemonic_VRR(mnemonic, format, opcode)
   295  	case "VRS-a", "VRS-b", "VRS-c", "VRS-d":
   296  		mn, enc = mnemonic_VRS(mnemonic, format, opcode)
   297  	case "VRV":
   298  		mn, enc = mnemonic_VRV(mnemonic, opcode)
   299  	case "VRX":
   300  		mn, enc = mnemonic_VRX(mnemonic, opcode)
   301  	case "VSI":
   302  		mn, enc = mnemonic_VSI(mnemonic, opcode)
   303  	default:
   304  		mn = mnemonic
   305  	}
   306  	return mn, enc
   307  }
   308  
   309  func mnemonic_E(mnemonic, opcode string) (string, string) {
   310  	var enc string
   311  	val, _ := strconv.ParseUint(opcode, 16, 16)
   312  	str := strconv.Itoa(int(val))
   313  	enc = str + "@0|??@16"
   314  	return mnemonic, enc
   315  }
   316  
   317  func mnemonic_I(mnemonic, opcode string) (string, string) {
   318  	var enc string
   319  	mnemonic += " I"
   320  	val, _ := strconv.ParseUint(opcode, 16, 16)
   321  	str := strconv.Itoa(int(val))
   322  	enc = str + "@0|I@8|??@16"
   323  	return mnemonic, enc
   324  }
   325  
   326  func mnemonic_IE(mnemonic, opcode string) (string, string) {
   327  	var enc string
   328  	mnemonic += " I1,I2"
   329  	val, _ := strconv.ParseUint(opcode, 16, 16)
   330  	str := strconv.Itoa(int(val))
   331  	enc = str + "@0|//@16|I1@24|I2@28|??@32"
   332  	return mnemonic, enc
   333  }
   334  
   335  func mnemonic_MII(mnemonic, opcode string) (string, string) {
   336  	var enc string
   337  	mnemonic += " M1,RI2,RI3"
   338  	val, _ := strconv.ParseUint(opcode, 16, 16)
   339  	str := strconv.Itoa(int(val))
   340  	enc = str + "@0|M1@8|RI2@12|RI3@24|??@48"
   341  	return mnemonic, enc
   342  }
   343  
   344  func mnemonic_RI(mnemonic, format, opcode string) (string, string) {
   345  	var enc string
   346  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   347  	str1 := strconv.Itoa(int(val1))
   348  	val2, _ := strconv.ParseUint(opcode[2:3], 16, 16)
   349  	str2 := strconv.Itoa(int(val2))
   350  	switch format {
   351  	case "RI-a":
   352  		mnemonic += " R1,I2"
   353  		enc = str1 + "@0|R1@8|" + str2 + "@12|I2@16|??@32"
   354  	case "RI-b":
   355  		mnemonic += " R1,RI2"
   356  		enc = str1 + "@0|R1@8|" + str2 + "@12|RI2@16|??@32"
   357  	case "RI-c":
   358  		mnemonic += " M1,RI2"
   359  		enc = str1 + "@0|M1@8|" + str2 + "@12|RI2@16|??@32"
   360  	}
   361  	return mnemonic, enc
   362  }
   363  
   364  func mnemonic_RIE(mnemonic, format, opcode string) (string, string) {
   365  	var enc string
   366  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   367  	str1 := strconv.Itoa(int(val1))
   368  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   369  	str2 := strconv.Itoa(int(val2))
   370  	switch format {
   371  	case "RIE-a":
   372  		mnemonic += " R1,I2,M3"
   373  		enc = str1 + "@0|R1@8|//@12|I2@16|M3@32|//@36|" + str2 + "@40|??@48"
   374  	case "RIE-b":
   375  		mnemonic += " R1,R2,M3,RI4"
   376  		enc = str1 + "@0|R1@8|R2@12|RI4@16|M3@32|//@36|" + str2 + "@40|??@48"
   377  	case "RIE-c":
   378  		mnemonic += " R1,I2,M3,RI4"
   379  		enc = str1 + "@0|R1@8|M3@12|RI4@16|I2@32|" + str2 + "@40|??@48"
   380  	case "RIE-d":
   381  		mnemonic += " R1,R3,I2"
   382  		enc = str1 + "@0|R1@8|R3@12|I2@16|//@32|" + str2 + "@40|??@48"
   383  	case "RIE-e":
   384  		mnemonic += " R1,R3,RI2"
   385  		enc = str1 + "@0|R1@8|R3@12|RI2@16|//@32|" + str2 + "@40|??@48"
   386  	case "RIE-f":
   387  		mnemonic += " R1,R2,I3,I4,I5"
   388  		enc = str1 + "@0|R1@8|R2@12|I3@16|I4@24|I5@32|" + str2 + "@40|??@48"
   389  	case "RIE-g":
   390  		mnemonic += " R1,I2,M3"
   391  		enc = str1 + "@0|R1@8|M3@12|I2@16|//@32|" + str2 + "@40|??@48"
   392  	}
   393  	return mnemonic, enc
   394  }
   395  
   396  func mnemonic_RIL(mnemonic, format, opcode string) (string, string) {
   397  	var enc string
   398  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   399  	str1 := strconv.Itoa(int(val1))
   400  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   401  	str2 := strconv.Itoa(int(val2))
   402  	switch format {
   403  	case "RIL-a":
   404  		mnemonic += " R1,I2"
   405  		enc = str1 + "@0|R1@8|" + str2 + "@12|I2@16|??@48"
   406  	case "RIL-b":
   407  		mnemonic += " R1,RI2"
   408  		enc = str1 + "@0|R1@8|" + str2 + "@12|RI2@16|??@48"
   409  	case "RIL-c":
   410  		mnemonic += " M1,RI2"
   411  		enc = str1 + "@0|M1@8|" + str2 + "@12|RI2@16|??@48"
   412  	}
   413  	return mnemonic, enc
   414  }
   415  
   416  func mnemonic_RIS(mnemonic, opcode string) (string, string) {
   417  	var enc string
   418  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   419  	str1 := strconv.Itoa(int(val1))
   420  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   421  	str2 := strconv.Itoa(int(val2))
   422  	mnemonic += " R1,I2,M3,D4(B4)"
   423  	enc = str1 + "@0|R1@8|M3@12|B4@16|D4@20|I2@32|" + str2 + "@40|??@48"
   424  	return mnemonic, enc
   425  }
   426  
   427  func mnemonic_RR(mnemonic, opcode string) (string, string) {
   428  	var enc string
   429  	val, _ := strconv.ParseUint(opcode, 16, 16)
   430  	str := strconv.Itoa(int(val))
   431  	switch mnemonic {
   432  	case "BCR":
   433  		mnemonic += " M1,R2"
   434  		enc = str + "@0|M1@8|R2@12|??@16"
   435  	case "SPM":
   436  		mnemonic += " R1"
   437  		enc = str + "@0|R1@8|//@12|??@16"
   438  	default:
   439  		mnemonic += " R1,R2"
   440  		enc = str + "@0|R1@8|R2@12|??@16"
   441  	}
   442  	return mnemonic, enc
   443  }
   444  
   445  func mnemonic_RRD(mnemonic, opcode string) (string, string) {
   446  	var enc string
   447  	mnemonic += " R1,R3,R2"
   448  	val, _ := strconv.ParseUint(opcode, 16, 16)
   449  	str := strconv.Itoa(int(val))
   450  	enc = str + "@0|R1@16|//@20|R3@24|R2@28|??@32"
   451  	return mnemonic, enc
   452  }
   453  
   454  func mnemonic_RRE(mnemonic, opcode string) (string, string) {
   455  	var enc string
   456  	val, _ := strconv.ParseUint(opcode, 16, 16)
   457  	str := strconv.Itoa(int(val))
   458  	switch mnemonic {
   459  	case "LZER", "LZDR", "LZXR", "EFPC", "EPAR", "EPAIR", "ESEA", "ESAIR", "ESAR", "ETND", "IAC", "IPM", "MSTA", "PTF", "SFASR", "SFPC", "SSAR", "SSAIR":
   460  		mnemonic += " R1"
   461  		enc = str + "@0|//@16|R1@24|//@28|??@32"
   462  	case "NNPA", "PALB", "PCC", "PCKMO":
   463  		enc = str + "@0|//@16|??@32"
   464  	default:
   465  		mnemonic += " R1,R2"
   466  		enc = str + "@0|//@16|R1@24|R2@28|??@32"
   467  	}
   468  	return mnemonic, enc
   469  }
   470  
   471  func mnemonic_RRF(mnemonic, format, opcode string) (string, string) {
   472  	var enc string
   473  	val, _ := strconv.ParseUint(opcode, 16, 16)
   474  	str := strconv.Itoa(int(val))
   475  	switch format {
   476  	case "RRF-a":
   477  		switch mnemonic {
   478  		case "SELR", "SELGR", "SELFHR", "IPTE", "AXTRA", "ADTRA",
   479  			"DDTRA", "DXTRA", "MDTRA", "MXTRA", "SDTRA", "SXTRA":
   480  			mnemonic += " R1,R2,R3,M4"
   481  			enc = str + "@0|R3@16|M4@20|R1@24|R2@28|??@32"
   482  		default:
   483  			mnemonic += " R1,R2,R3"
   484  			enc = str + "@0|R3@16|//@20|R1@24|R2@28|??@32"
   485  		}
   486  	case "RRF-b":
   487  		switch mnemonic {
   488  		case "CRDTE", "IDTE", "LPTEA", "RDP", "DIEBR", "DIDBR",
   489  			"QADTR", "QAXTR", "RRDTR", "RRXTR":
   490  			mnemonic += " R1,R3,R2,M4"
   491  			enc = str + "@0|R3@16|M4@20|R1@24|R2@28|??@32"
   492  		default:
   493  			mnemonic += " R1,R3,R2"
   494  			enc = str + "@0|R3@16|//@20|R1@24|R2@28|??@32"
   495  		}
   496  	case "RRF-c":
   497  		mnemonic += " R1,R2,M3"
   498  		enc = str + "@0|M3@16|//@20|R1@24|R2@28|??@32"
   499  	case "RRF-d":
   500  		mnemonic += " R1,R2,M4"
   501  		enc = str + "@0|//@16|M4@20|R1@24|R2@28|??@32"
   502  	case "RRF-e":
   503  		switch mnemonic {
   504  		case "CXFBRA", "CXFTR", "CDFBRA", "CDFTR", "CEFBRA", "CXGBRA", "CXGTRA", "CDGBRA", "CDGTRA", "CEGBRA", "CXLFBR", "CXLFTR", "CDLFBR", "CDLFTR", "CELFBR",
   505  			"CXLGBR", "CXLGTR", "CDLGBR", "CDLGTR", "CELGBR", "CFXBRA", "CGXBRA", "CFXTR", "CGXTRA", "CFDBRA", "CGDBRA", "CFDTR", "CGDTRA", "CFEBRA", "CGEBRA",
   506  			"CLFEBR", "CLFDBR", "CLFXBR", "CLGEBR", "CLGDBR", "CLGXBR", "CLFXTR", "CLFDTR", "CLGXTR", "CLGDTR", "FIEBRA", "FIDBRA", "FIXBRA", "FIDTR", "FIXTR",
   507  			"LDXBRA", "LEDBRA", "LEXBRA", "LEDTR", "LDXTR":
   508  			mnemonic += " R1,M3,R2,M4"
   509  			enc = str + "@0|M3@16|M4@20|R1@24|R2@28|??@32"
   510  		default:
   511  			mnemonic += " R1,M3,R2"
   512  			enc = str + "@0|M3@16|//@20|R1@24|R2@28|??@32"
   513  		}
   514  	}
   515  	return mnemonic, enc
   516  }
   517  
   518  func mnemonic_RRS(mnemonic, opcode string) (string, string) {
   519  	var enc string
   520  	mnemonic += " R1,R2,M3,D4(B4)"
   521  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   522  	str1 := strconv.Itoa(int(val1))
   523  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   524  	str2 := strconv.Itoa(int(val2))
   525  	enc = str1 + "@0|R1@8|R2@12|B4@16|D4@20|M3@32|//@36|" + str2 + "@40|??@48"
   526  	return mnemonic, enc
   527  }
   528  
   529  func mnemonic_RS(mnemonic, format, opcode string) (string, string) {
   530  	var enc string
   531  	val, _ := strconv.ParseUint(opcode, 16, 16)
   532  	str := strconv.Itoa(int(val))
   533  	switch format {
   534  	case "RS-a":
   535  		switch mnemonic {
   536  		case "SLDA", "SLDL", "SLA", "SLL", "SRA", "SRDA", "SRDL", "SRL":
   537  			mnemonic += " R1,D2(B2)"
   538  			enc = str + "@0|R1@8|//@12|B2@16|D2@20|??@32"
   539  		default:
   540  			mnemonic += " R1,R3,D2(B2)"
   541  			enc = str + "@0|R1@8|R3@12|B2@16|D2@20|??@32"
   542  		}
   543  	case "RS-b":
   544  		mnemonic += " R1,M3,D2(B2)"
   545  		enc = str + "@0|R1@8|M3@12|B2@16|D2@20|??@32"
   546  	}
   547  	return mnemonic, enc
   548  }
   549  
   550  func mnemonic_RSI(mnemonic, opcode string) (string, string) {
   551  	var enc string
   552  	mnemonic += " R1,R3,RI2"
   553  	val, _ := strconv.ParseUint(opcode, 16, 16)
   554  	str := strconv.Itoa(int(val))
   555  	enc = str + "@0|R1@8|R3@12|RI2@16|??@32"
   556  	return mnemonic, enc
   557  }
   558  
   559  func mnemonic_RSL(mnemonic, format, opcode string) (string, string) {
   560  	var enc string
   561  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   562  	str1 := strconv.Itoa(int(val1))
   563  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   564  	str2 := strconv.Itoa(int(val2))
   565  	switch format {
   566  	case "RSL-a":
   567  		mnemonic += " D1(L1,B1)"
   568  		enc = str1 + "@0|L1@8|//@12|B1@16|D1@20|//@32|" + str2 + "@40|??@48"
   569  	case "RSL-b":
   570  		mnemonic += " R1,D2(L2,B2),M3"
   571  		enc = str1 + "@0|L2@8|B2@16|D2@20|R1@32|M3@36|" + str2 + "@40|??@48"
   572  	}
   573  	return mnemonic, enc
   574  }
   575  
   576  func mnemonic_RSY(mnemonic, format, opcode string) (string, string) {
   577  	var enc string
   578  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   579  	str1 := strconv.Itoa(int(val1))
   580  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   581  	str2 := strconv.Itoa(int(val2))
   582  	switch format {
   583  	case "RSY-a":
   584  		mnemonic += " R1,R3,D2(B2)"
   585  		enc = str1 + "@0|R1@8|R3@12|B2@16|D2@20|" + str2 + "@40|??@48"
   586  	case "RSY-b":
   587  		switch mnemonic {
   588  		case "LOC", "LOCFH", "LOCG", "STOCFH", "STOC", "STOCG":
   589  			mnemonic += " R1,D2(B2),M3"
   590  		default:
   591  			mnemonic += " R1,M3,D2(B2)"
   592  		}
   593  		enc = str1 + "@0|R1@8|M3@12|B2@16|D2@20|" + str2 + "@40|??@48"
   594  	}
   595  	return mnemonic, enc
   596  }
   597  
   598  func mnemonic_RX(mnemonic, format, opcode string) (string, string) {
   599  	var enc string
   600  	val, _ := strconv.ParseInt(opcode, 16, 16)
   601  	str := strconv.Itoa(int(val))
   602  	switch format {
   603  	case "RX-a":
   604  		mnemonic += " R1,D2(X2,B2)"
   605  		enc = str + "@0|R1@8|X2@12|B2@16|D2@20|??@32"
   606  	case "RX-b":
   607  		mnemonic += " M1,D2(X2,B2)"
   608  		enc = str + "@0|M1@8|X2@12|B2@16|D2@20|??@32"
   609  	}
   610  	return mnemonic, enc
   611  }
   612  
   613  func mnemonic_RXE(mnemonic, opcode string) (string, string) {
   614  	var enc string
   615  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   616  	str1 := strconv.Itoa(int(val1))
   617  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   618  	str2 := strconv.Itoa(int(val2))
   619  	switch mnemonic {
   620  	case "LCBB":
   621  		mnemonic += " R1,D2(X2,B2),M3"
   622  		enc = str1 + "@0|R1@8|X2@12|B2@16|D2@20|M3@32|//@36|" + str2 + "@40|??@48"
   623  	default:
   624  		mnemonic += " R1,D2(X2,B2)"
   625  		enc = str1 + "@0|R1@8|X2@12|B2@16|D2@20|//@32|" + str2 + "@40|??@48"
   626  	}
   627  	return mnemonic, enc
   628  }
   629  
   630  func mnemonic_RXF(mnemonic, opcode string) (string, string) {
   631  	var enc string
   632  	mnemonic += " R1,R3,D2(X2,B2)"
   633  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   634  	str1 := strconv.Itoa(int(val1))
   635  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   636  	str2 := strconv.Itoa(int(val2))
   637  	enc = str1 + "@0|R3@8|X2@12|B2@16|D2@20|R1@32|//@36|" + str2 + "@40|??@48"
   638  	return mnemonic, enc
   639  }
   640  
   641  func mnemonic_RXY(mnemonic, format, opcode string) (string, string) {
   642  	var enc string
   643  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   644  	str1 := strconv.Itoa(int(val1))
   645  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   646  	str2 := strconv.Itoa(int(val2))
   647  	switch format {
   648  	case "RXY-a":
   649  		mnemonic += " R1,D2(X2,B2)"
   650  		enc = str1 + "@0|R1@8|X2@12|B2@16|D2@20|" + str2 + "@40|??@48"
   651  	case "RXY-b":
   652  		mnemonic += " M1,D2(X2,B2)"
   653  		enc = str1 + "@0|M1@8|X2@12|B2@16|D2@20|" + str2 + "@40|??@48"
   654  	}
   655  	return mnemonic, enc
   656  }
   657  
   658  func mnemonic_S(mnemonic, opcode string) (string, string) {
   659  	var enc string
   660  	val, _ := strconv.ParseUint(opcode, 16, 16)
   661  	str := strconv.Itoa(int(val))
   662  	switch mnemonic {
   663  	case "PTLB", "TEND", "XSCH", "CSCH", "HSCH", "IPK", "RCHP", "RSCH", "SAL", "SCHM":
   664  		enc = str + "@0|//@16|??@32"
   665  	default:
   666  		mnemonic += " D2(B2)"
   667  		enc = str + "@0|B2@16|D2@20|??@32"
   668  	}
   669  	return mnemonic, enc
   670  }
   671  
   672  func mnemonic_SI(mnemonic, opcode string) (string, string) {
   673  	var enc string
   674  	val, _ := strconv.ParseUint(opcode, 16, 16)
   675  	str := strconv.Itoa(int(val))
   676  	switch mnemonic {
   677  	case "TS", "SSM", "LPSW":
   678  		mnemonic += " D1(B1)"
   679  	default:
   680  		mnemonic += " D1(B1),I2"
   681  	}
   682  	enc = str + "@0|I2@8|B1@16|D1@20|??@32"
   683  	return mnemonic, enc
   684  }
   685  
   686  func mnemonic_SIL(mnemonic, opcode string) (string, string) {
   687  	var enc string
   688  	mnemonic += " D1(B1),I2"
   689  	val, _ := strconv.ParseUint(opcode, 16, 16)
   690  	str := strconv.Itoa(int(val))
   691  	enc = str + "@0|B1@16|D1@20|I2@32|??@48"
   692  	return mnemonic, enc
   693  }
   694  
   695  func mnemonic_SIY(mnemonic, opcode string) (string, string) {
   696  	var enc string
   697  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   698  	str1 := strconv.Itoa(int(val1))
   699  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   700  	str2 := strconv.Itoa(int(val2))
   701  	switch mnemonic {
   702  	case "LPSWEY":
   703  		mnemonic += " D1(B1)"
   704  		enc = str1 + "@0|//@8|B1@16|D1@20|" + str2 + "@40|??@48"
   705  	default:
   706  		mnemonic += " D1(B1),I2"
   707  		enc = str1 + "@0|I2@8|B1@16|D1@20|" + str2 + "@40|??@48"
   708  	}
   709  	return mnemonic, enc
   710  }
   711  
   712  func mnemonic_SMI(mnemonic, opcode string) (string, string) {
   713  	var enc string
   714  	mnemonic += " M1,RI2,D3(B3)"
   715  	val, _ := strconv.ParseUint(opcode, 16, 16)
   716  	str := strconv.Itoa(int(val))
   717  	enc = str + "@0|M1@8|//@12|B3@16|D3@20|RI2@32|??@48"
   718  	return mnemonic, enc
   719  }
   720  
   721  func mnemonic_SS(mnemonic, format, opcode string) (string, string) {
   722  	var enc string
   723  	val, _ := strconv.ParseUint(opcode, 16, 16)
   724  	str := strconv.Itoa(int(val))
   725  	switch format {
   726  	case "SS-a":
   727  		mnemonic += " D1(L1,B1),D2(B2)"
   728  		enc = str + "@0|L1@8|B1@16|D1@20|B2@32|D2@36|??@48"
   729  	case "SS-b":
   730  		mnemonic += " D1(L1,B1),D2(L2,B2)"
   731  		enc = str + "@0|L1@8|L2@12|B1@16|D1@20|B2@32|D2@36|??@48"
   732  	case "SS-c":
   733  		mnemonic += " D1(L1,B1),D2(B2),I3"
   734  		enc = str + "@0|L1@8|I3@12|B1@16|D1@20|B2@32|D2@36|??@48"
   735  	case "SS-d":
   736  		mnemonic += " D1(R1,B1),D2(B2),R3"
   737  		enc = str + "@0|R1@8|R3@12|B1@16|D1@20|B2@32|D2@36|??@48"
   738  	case "SS-e":
   739  		switch mnemonic {
   740  		case "LMD":
   741  			mnemonic += " R1,R3,D2(B2),D4(B4)"
   742  		default:
   743  			mnemonic += " R1,D2(B2),R3,D4(B4)"
   744  		}
   745  		enc = str + "@0|R1@8|R3@12|B2@16|D2@20|B4@32|D4@36|??@48"
   746  	case "SS-f":
   747  		mnemonic += " D1(B1),D2(L2,B2)"
   748  		enc = str + "@0|L2@8|B1@16|D1@20|B2@32|D2@36|??@48"
   749  	}
   750  	return mnemonic, enc
   751  
   752  }
   753  
   754  func mnemonic_SSE(mnemonic, opcode string) (string, string) {
   755  	var enc string
   756  	mnemonic += " D1(B1),D2(B2)"
   757  	val, _ := strconv.ParseUint(opcode, 16, 16)
   758  	str := strconv.Itoa(int(val))
   759  	enc = str + "@0|B1@16|D1@20|B2@32|D2@36|??@48"
   760  	return mnemonic, enc
   761  }
   762  
   763  func mnemonic_SSF(mnemonic, opcode string) (string, string) {
   764  	var enc string
   765  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   766  	str1 := strconv.Itoa(int(val1))
   767  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   768  	str2 := strconv.Itoa(int(val2))
   769  	switch mnemonic {
   770  	case "LPD", "LPDG":
   771  		mnemonic += " R3,D1(B1),D2(B2)"
   772  	default:
   773  		mnemonic += " D1(B1),D2(B2),R3"
   774  	}
   775  	enc = str1 + "@0|R3@8|" + str2 + "@12|B1@16|D1@20|B2@32|D2@36|??@48"
   776  	return mnemonic, enc
   777  }
   778  
   779  func mnemonic_VRI(mnemonic, format, opcode string) (string, string) {
   780  	var enc string
   781  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   782  	str1 := strconv.Itoa(int(val1))
   783  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   784  	str2 := strconv.Itoa(int(val2))
   785  	switch format {
   786  	case "VRI-a":
   787  		if strings.Contains(mnemonic, "VGBM") { // Check for M3 field
   788  			mnemonic += " V1,I2"
   789  			enc = str1 + "@0|V1@8|//@12|I2@16|//@32|RXB@36|" + str2 + "@40|??@48"
   790  		} else {
   791  			mnemonic += " V1,I2,M3"
   792  			enc = str1 + "@0|V1@8|//@12|I2@16|M3@32|RXB@36|" + str2 + "@40|??@48"
   793  		}
   794  	case "VRI-b":
   795  		mnemonic += " V1,I2,I3,M4"
   796  		enc = str1 + "@0|V1@8|//@12|I2@16|I3@24|M4@32|RXB@36|" + str2 + "@40|??@48"
   797  	case "VRI-c":
   798  		mnemonic += " V1,V3,I2,M4"
   799  		enc = str1 + "@0|V1@8|V3@12|I2@16|M4@32|RXB@36|" + str2 + "@40|??@48"
   800  	case "VRI-d":
   801  		if strings.Contains(mnemonic, "VERIM") { // Check for M5 field
   802  			mnemonic += " V1,V2,V3,I4,M5"
   803  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|I4@24|M5@32|RXB@36|" + str2 + "@40|??@48"
   804  		} else {
   805  			mnemonic += " V1,V2,V3,I4"
   806  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|I4@24|//@32|RXB@36|" + str2 + "@40|??@48"
   807  		}
   808  	case "VRI-e":
   809  		mnemonic += " V1,V2,I3,M4,M5"
   810  		enc = str1 + "@0|V1@8|V2@12|I3@16|M5@28|M4@32|RXB@36|" + str2 + "@40|??@48"
   811  	case "VRI-f":
   812  		mnemonic += " V1,V2,V3,I4,M5"
   813  		enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M5@24|I4@28|RXB@36|" + str2 + "@40|??@48"
   814  	case "VRI-g":
   815  		mnemonic += " V1,V2,I3,I4,M5"
   816  		enc = str1 + "@0|V1@8|V2@12|I4@16|M5@24|I3@28|RXB@36|" + str2 + "@40|??@48"
   817  	case "VRI-h":
   818  		mnemonic += " V1,I2,I3"
   819  		enc = str1 + "@0|V1@8|//@12|I2@16|I3@32|RXB@36|" + str2 + "@40|??@48"
   820  	case "VRI-i":
   821  		mnemonic += " V1,R2,I3,M4"
   822  		enc = str1 + "@0|V1@8|R2@12|//@16|M4@24|I3@28|RXB@36|" + str2 + "@40|??@48"
   823  	}
   824  	return mnemonic, enc
   825  }
   826  
   827  func mnemonic_VRR(mnemonic, format, opcode string) (string, string) {
   828  	var enc string
   829  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   830  	str1 := strconv.Itoa(int(val1))
   831  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   832  	str2 := strconv.Itoa(int(val2))
   833  	switch format {
   834  	case "VRR-a":
   835  		switch mnemonic {
   836  		case "VLR", "VTM": // V1,V2
   837  			mnemonic += " V1,V2"
   838  			enc = str1 + "@0|V1@8|V2@12|//@16|RXB@36|" + str2 + "@40|??@48"
   839  
   840  		case "VSEG", "VUPH", "VUPLH", "VUPL", "VUPLL", "VCLZ", "VCTZ", "VEC", "VECL", "VLC", "VLP", "VPOPCT": // V1,V2,M3
   841  			mnemonic += " V1,V2,M3"
   842  			enc = str1 + "@0|V1@8|V2@12|//@16|M3@32|RXB@36|" + str2 + "@40|??@48"
   843  
   844  		case "VISTR": // V1,V2,M3,M5
   845  			mnemonic += " V1,V2,M3,M5"
   846  			enc = str1 + "@0|V1@8|V2@12|//@16|M5@24|//@28|M3@32|RXB@36|" + str2 + "@40|??@48"
   847  
   848  		case "WFC", "WFK", "VFLL", "VFSQ", "VCLFNH", "VCLFNL", "VCFN", "VCNF": // V1,V2,M3,M4
   849  			mnemonic += " V1,V2,M3,M4"
   850  			enc = str1 + "@0|V1@8|V2@12|//@16|M4@28|M3@32|RXB@36|" + str2 + "@40|??@48"
   851  
   852  		case "VCFPS", "VCDG", "VCDLG", "VCGD", "VCFPL", "VCSFP", "VCLFP", "VCLGD", "VFI", "VFLR", "VFPSO": // V1,V2,M3,M4,M5
   853  			mnemonic += " V1,V2,M3,M4,M5"
   854  			enc = str1 + "@0|V1@8|V2@12|//@16|M5@24|M4@28|M3@32|RXB@36|" + str2 + "@40|??@48"
   855  		}
   856  	case "VRR-b":
   857  		switch mnemonic {
   858  		case "VSCSHP":
   859  			mnemonic += " V1,V2,V3"
   860  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|RXB@36|" + str2 + "@40|??@48"
   861  		default:
   862  			mnemonic += " V1,V2,V3,M4,M5"
   863  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M5@24|//@28|M4@32|RXB@36|" + str2 + "@40|??@48"
   864  		}
   865  	case "VRR-c":
   866  		switch mnemonic {
   867  		case "VFA", "VFD", "VFM", "VFS", "VCRNF": // V1,V2,V3,M4,M5
   868  			mnemonic += " V1,V2,V3,M4,M5"
   869  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M5@28|M4@32|RXB@36|" + str2 + "@40|??@48"
   870  
   871  		case "VFCE", "VFCH", "VFCHE", "VFMAX", "VFMIN": // V1,V2,V3,M4,M5,M6
   872  			mnemonic += " V1,V2,V3,M4,M5,M6"
   873  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M6@24|M5@28|M4@32|RXB@36|" + str2 + "@40|??@48"
   874  
   875  		case "VBPERM", "VN", "VNC", "VCKSM", "VX", "VNN", "VNO", "VNX",
   876  			"VO", "VOC", "VSL", "VSLB", "VSRA", "VSRAB", "VSRL", "VSRLB": // V1,V2,V3
   877  			mnemonic += " V1,V2,V3"
   878  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|RXB@36|" + str2 + "@40|??@48"
   879  		default: // V1,V2,V3,M4
   880  			mnemonic += " V1,V2,V3,M4"
   881  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M4@32|RXB@36|" + str2 + "@40|??@48"
   882  		}
   883  	case "VRR-d":
   884  		switch mnemonic {
   885  		case "VMSL", "VSTRC", "VSTRS": // V1,V2,V3,V4,M5,M6
   886  			mnemonic += " V1,V2,V3,V4,M5,M6"
   887  			enc = str1 + "@0|V1@8|V2@12|V3@16|M5@20|M6@24|//@28|V4@32|RXB@36|" + str2 + "@40|??@48"
   888  		default:
   889  			mnemonic += " V1,V2,V3,V4,M5"
   890  			enc = str1 + "@0|V1@8|V2@12|V3@16|M5@20|//@24|V4@32|RXB@36|" + str2 + "@40|??@48"
   891  		}
   892  	case "VRR-e":
   893  		switch mnemonic {
   894  		case "VPERM", "VSEL":
   895  			mnemonic += " V1,V2,V3,V4"
   896  			enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|V4@32|RXB@36|" + str2 + "@40|??@48"
   897  		default:
   898  			mnemonic += " V1,V2,V3,V4,M5,M6"
   899  			enc = str1 + "@0|V1@8|V2@12|V3@16|M6@20|//@24|M5@28|V4@32|RXB@36|" + str2 + "@40|??@48"
   900  		}
   901  	case "VRR-f":
   902  		mnemonic += " V1,R2,R3"
   903  		enc = str1 + "@0|V1@8|R2@12|R3@16|//@20|RXB@36|" + str2 + "@40|??@48"
   904  	case "VRR-g":
   905  		mnemonic += " V1"
   906  		enc = str1 + "@0|//@8|V1@12|//@16|RXB@36|" + str2 + "@40|??@48"
   907  	case "VRR-h":
   908  		mnemonic += " V1,V2,M3"
   909  		enc = str1 + "@0|//@8|V1@12|V2@16|//@20|M3@24|//@28|RXB@36|" + str2 + "@40|??@48"
   910  	case "VRR-i":
   911  		mnemonic += " R1,V2,M3,M4"
   912  		enc = str1 + "@0|R1@8|V2@12|//@16|M3@24|M4@28|//@32|RXB@36|" + str2 + "@40|??@48"
   913  	case "VRR-j":
   914  		mnemonic += " V1,V2,V3,M4"
   915  		enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M4@24|//@28|RXB@36|" + str2 + "@40|??@48"
   916  	case "VRR-k":
   917  		mnemonic += " V1,V2,M3"
   918  		enc = str1 + "@0|V1@8|V2@12|//@16|M3@24|//@28|RXB@36|" + str2 + "@40|??@48"
   919  	}
   920  	return mnemonic, enc
   921  }
   922  
   923  func mnemonic_VRS(mnemonic, format, opcode string) (string, string) {
   924  	var enc string
   925  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   926  	str1 := strconv.Itoa(int(val1))
   927  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   928  	str2 := strconv.Itoa(int(val2))
   929  	switch format {
   930  	case "VRS-a":
   931  		mnemonic += " V1,V3,D2(B2),M4"
   932  		enc = str1 + "@0|V1@8|V3@12|B2@16|D2@20|M4@32|RXB@36|" + str2 + "@40|??@48"
   933  	case "VRS-b":
   934  		if strings.Contains(mnemonic, "VLVG") {
   935  			mnemonic += " V1,R3,D2(B2),M4"
   936  			enc = str1 + "@0|V1@8|R3@12|B2@16|D2@20|M4@32|RXB@36|" + str2 + "@40|??@48"
   937  		} else {
   938  			mnemonic += " V1,R3,D2(B2)"
   939  			enc = str1 + "@0|V1@8|R3@12|B2@16|D2@20|//@32|RXB@36|" + str2 + "@40|??@48"
   940  		}
   941  	case "VRS-c":
   942  		mnemonic += " R1,V3,D2(B2),M4"
   943  		enc = str1 + "@0|R1@8|V3@12|B2@16|D2@20|M4@32|RXB@36|" + str2 + "@40|??@48"
   944  	case "VRS-d":
   945  		mnemonic += " V1,R3,D2(B2)"
   946  		enc = str1 + "@0|//@8|R3@12|B2@16|D2@20|V1@32|RXB@36|" + str2 + "@40|??@48"
   947  	}
   948  	return mnemonic, enc
   949  }
   950  
   951  func mnemonic_VRV(mnemonic, opcode string) (string, string) {
   952  	var enc string
   953  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   954  	str1 := strconv.Itoa(int(val1))
   955  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   956  	str2 := strconv.Itoa(int(val2))
   957  	mnemonic += " V1,D2(V2,B2),M3"
   958  	enc = str1 + "@0|V1@8|V2@12|B2@16|D2@20|M3@32|RXB@36|" + str2 + "@40|??@48"
   959  	return mnemonic, enc
   960  }
   961  
   962  func mnemonic_VRX(mnemonic, opcode string) (string, string) {
   963  	var enc string
   964  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   965  	str1 := strconv.Itoa(int(val1))
   966  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   967  	str2 := strconv.Itoa(int(val2))
   968  	mnemonic += " V1,D2(X2,B2),M3"
   969  	enc = str1 + "@0|V1@8|X2@12|B2@16|D2@20|M3@32|RXB@36|" + str2 + "@40|??@48"
   970  	return mnemonic, enc
   971  }
   972  
   973  func mnemonic_VSI(mnemonic, opcode string) (string, string) {
   974  	var enc string
   975  	mnemonic += " V1,D2(B2),I3"
   976  	val1, _ := strconv.ParseUint(opcode[:2], 16, 16)
   977  	str1 := strconv.Itoa(int(val1))
   978  	val2, _ := strconv.ParseUint(opcode[2:], 16, 16)
   979  	str2 := strconv.Itoa(int(val2))
   980  	enc = str1 + "@0|I3@8|B2@16|D2@20|V1@32|RXB@36|" + str2 + "@40|??@48"
   981  	return mnemonic, enc
   982  }
   983  
   984  func matchXCord(t pdf.Text, Xcord float64) bool {
   985  	return math.Abs(t.X-Xcord) < 0.9
   986  }
   987  
   988  func match(t pdf.Text, font string, size float64, substr string) bool {
   989  	return t.Font == font && (size == 0 || math.Abs(t.FontSize-size) < 0.2) && strings.Contains(t.S, substr)
   990  }
   991  
   992  func findWords(chars []pdf.Text) (words []pdf.Text) {
   993  	// Sort by Y coordinate and normalize.
   994  	const nudge = 1.5
   995  	sort.Sort(pdf.TextVertical(chars))
   996  	old := -100000.0
   997  	for i, c := range chars {
   998  		if c.Y != old && math.Abs(old-c.Y) < nudge {
   999  			chars[i].Y = old
  1000  		} else {
  1001  			old = c.Y
  1002  		}
  1003  	}
  1004  
  1005  	// Sort by Y coordinate, breaking ties with X.
  1006  	// This will bring letters in a single word together.
  1007  	sort.Sort(pdf.TextVertical(chars))
  1008  
  1009  	// Loop over chars.
  1010  	for i := 0; i < len(chars); {
  1011  		// Find all chars on line.
  1012  		j := i + 1
  1013  		for j < len(chars) && chars[j].Y == chars[i].Y {
  1014  			j++
  1015  		}
  1016  		var end float64
  1017  		// Split line into words (really, phrases).
  1018  		for k := i; k < j; {
  1019  			ck := &chars[k]
  1020  			s := ck.S
  1021  			end = ck.X + ck.W
  1022  			charSpace := ck.FontSize / 6
  1023  			wordSpace := ck.FontSize * 2 / 3
  1024  			l := k + 1
  1025  			for l < j {
  1026  				// Grow word.
  1027  				cl := &chars[l]
  1028  				if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+charSpace {
  1029  					s += cl.S
  1030  					end = cl.X + cl.W
  1031  					l++
  1032  					continue
  1033  				}
  1034  				// Add space to phrase before next word.
  1035  				if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+wordSpace {
  1036  					s += " " + cl.S
  1037  					end = cl.X + cl.W
  1038  					l++
  1039  					continue
  1040  				}
  1041  				break
  1042  			}
  1043  			f := ck.Font
  1044  			f = strings.TrimSuffix(f, ",Italic")
  1045  			f = strings.TrimSuffix(f, "-Italic")
  1046  			words = append(words, pdf.Text{
  1047  				Font:     f,
  1048  				FontSize: ck.FontSize,
  1049  				X:        ck.X,
  1050  				Y:        ck.Y,
  1051  				W:        end - ck.X,
  1052  				S:        s,
  1053  			})
  1054  			k = l
  1055  		}
  1056  		i = j
  1057  	}
  1058  	return words
  1059  }
  1060  
  1061  func sameFont(f1, f2 string) bool {
  1062  	f1 = strings.TrimSuffix(f1, ",Italic")
  1063  	f1 = strings.TrimSuffix(f1, "-Italic")
  1064  	f2 = strings.TrimSuffix(f1, ",Italic")
  1065  	f2 = strings.TrimSuffix(f1, "-Italic")
  1066  	return strings.TrimSuffix(f1, ",Italic") == strings.TrimSuffix(f2, ",Italic") || f1 == "Symbol" || f2 == "Symbol" || f1 == "TimesNewRoman" || f2 == "TimesNewRoman"
  1067  }