678 lines
20 KiB
Typst
678 lines
20 KiB
Typst
#import ".template.typ": *
|
|
#show: conf
|
|
|
|
#title[AIN-48 Instruction Set Architecture]
|
|
#align(center, grid(
|
|
columns: 4,
|
|
column-gutter: .5em,
|
|
align: left + horizon,
|
|
row-gutter: .5em,
|
|
grid.cell(rowspan: 2)[Architectúra],
|
|
[Internátionális],
|
|
[Nórmae],
|
|
grid.cell(rowspan: 2)[--- 48 bit],
|
|
[Intstrúctiónum],
|
|
[Numerátiónum],
|
|
))
|
|
|
|
#show heading: set text(weight: 900)
|
|
#show heading: it => [
|
|
#set par(justify: false)
|
|
#grid(columns: (auto, 1fr), column-gutter: .25em, if it.numbering != none {
|
|
context [#counter(heading).display(it.numbering)]
|
|
} else [], it.body)
|
|
]
|
|
= Conventions
|
|
|
|
A *byte* (singulus) is the smallest adressable part of memory, that is, a 12-bit
|
|
binary number.
|
|
|
|
A *word* (quaternus) is a binary number composed of 4 bytes, that is, a 48 bit
|
|
binary number.
|
|
|
|
In memory, multibyte numbers are laid out with the least significant byte at the
|
|
lowest memory adress
|
|
|
|
= Registers
|
|
The main registers of the architecture are all word-length:
|
|
|
|
#columns(2)[
|
|
/ %0/%nul:Constant zero
|
|
/ %01: General purpose
|
|
/ %02: General purpose
|
|
/ %03: General purpose
|
|
/ %04: General purpose
|
|
/ %05: General purpose
|
|
/ %06: General purpose
|
|
/ %07: General purpose
|
|
/ %ia: Index ad actiónem\ (Instruction pointer)
|
|
#colbreak()
|
|
/ %10: General purpose
|
|
/ %11: General purpose
|
|
/ %12: General purpose
|
|
/ %13: General purpose
|
|
/ %14: General purpose
|
|
/ %15: General purpose
|
|
/ %16: General purpose
|
|
/ %17/%it: Index ad turrim\ (Stack pointer)
|
|
]
|
|
There is also a 3-bit status register.
|
|
|
|
= Instructions as encoded
|
|
|
|
In instruction diagrams, each large rectangle represents a byte, that are
|
|
disposed in memory as implied by the reading order, starting at the lowest
|
|
memory adress.
|
|
|
|
#let instruction_diagram(..bytes, voff: 0) = {
|
|
import cetz.draw: *
|
|
for (i, b) in bytes.pos().enumerate() {
|
|
let j = 0
|
|
for (l, d) in b {
|
|
content((i * 12.5 + j + l / 2, 1 + voff), d)
|
|
j = j + l
|
|
line((i * 12.5 + j, voff), (i * 12.5 + j, 2 + voff), stroke: gray)
|
|
}
|
|
rect((i * 12.5, voff), (i * 12.5 + 12, 2 + voff))
|
|
for j in range(0, 13) {
|
|
line((i * 12.5 + j, .125 + voff), (i * 12.5 + j, -.125 + voff))
|
|
line((i * 12.5 + j, 2.125 + voff), (i * 12.5 + j, 1.875 + voff))
|
|
}
|
|
content((i * 12.5, voff + 2.25), anchor: "south-west")[11]
|
|
content((i * 12.5 + 12, voff + 2.25), anchor: "south-east")[0]
|
|
}
|
|
}
|
|
|
|
#let amal = [Actió Machinae Arithméticae Logicaeque]
|
|
== #amal
|
|
|
|
#align(
|
|
center,
|
|
cetz.canvas(
|
|
{
|
|
import cetz.draw: *
|
|
scale(.65)
|
|
instruction_diagram((
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [i#sub[2]\ 0]),
|
|
(1, [i#sub[1]\ 0]),
|
|
(1, [s]),
|
|
(4, [op]),
|
|
), ((4, [r#sub[d]]), (4, [r#sub[2]]), (4, [r#sub[1]])))
|
|
content((12.25, -1))[or]
|
|
instruction_diagram(voff: -5, (
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [i#sub[2]\ 0]),
|
|
(1, [i#sub[1]\ 1]),
|
|
(1, [s]),
|
|
(4, [op]),
|
|
), ((4, [r#sub[d]]), (4, [r#sub[2]]), (4, text(size: .9em)[imm[0:3]])))
|
|
content((12.25, -6))[or]
|
|
instruction_diagram(voff: -10, (
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [i#sub[2]\ 1]),
|
|
(1, [i#sub[1]\ 0]),
|
|
(1, [s]),
|
|
(4, [op]),
|
|
), ((4, [r#sub[d]]), (4, text(size: .9em)[imm[0:3]]), (4, [r#sub[1]])))
|
|
content((12.25, -11))[or]
|
|
instruction_diagram(voff: -15, (
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [i#sub[2]\ 1]),
|
|
(1, [i#sub[1]\ 1]),
|
|
(1, [s]),
|
|
(4, [op]),
|
|
), ((4, [r#sub[d]]), (8, [imm[0:7]])))
|
|
},
|
|
),
|
|
)
|
|
|
|
#let iml = [Immediátum Magnum Lectura]
|
|
== #iml
|
|
|
|
#align(
|
|
center,
|
|
cetz.canvas(
|
|
{
|
|
import cetz.draw: *
|
|
scale(.65)
|
|
instruction_diagram((
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [1]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [s]),
|
|
(4, [r]),
|
|
), ((12, [imm[0:11]]),))
|
|
instruction_diagram(((12, [imm[12:23]]),), ((12, [ımm[24:35]]),), voff: -3)
|
|
instruction_diagram(((12, [imm[36:47]]),), voff: -6)
|
|
},
|
|
),
|
|
)
|
|
|
|
#let ipl = [Immediátum Parvum Lectura]
|
|
== #ipl
|
|
|
|
#align(center, cetz.canvas({
|
|
import cetz.draw: *
|
|
scale(.65)
|
|
instruction_diagram((
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [s]),
|
|
(4, [r]),
|
|
), ((12, [imm[0:11]]),))
|
|
}))
|
|
|
|
#let amls = [Ad Memóriam Lectura Scripturaque]
|
|
== #amls
|
|
#align(center, cetz.canvas({
|
|
import cetz.draw: *
|
|
scale(.65)
|
|
instruction_diagram((
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [1]),
|
|
(1, [w]),
|
|
(4, [r#sub[d]]),
|
|
(4, [r#sub[a]]),
|
|
), ((12, [imm[0:11]]),))
|
|
}))
|
|
|
|
#let asss = [Actió Sequentiae Singulí Simplicis]
|
|
== #asss
|
|
#align(center, cetz.canvas({
|
|
import cetz.draw: *
|
|
scale(.65)
|
|
instruction_diagram((
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(3, [op]),
|
|
))
|
|
}))
|
|
|
|
#let asli = [Actió Sequentiae Locí Immediátí]
|
|
== #asli
|
|
|
|
#align(
|
|
center,
|
|
cetz.canvas(
|
|
{
|
|
import cetz.draw: *
|
|
scale(.65)
|
|
instruction_diagram((
|
|
(1, [1]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [0]),
|
|
(1, [I]),
|
|
(1, [C]),
|
|
(1, [N]),
|
|
(1, [Z]),
|
|
(1, [R]),
|
|
), ((12, [imm[0:11]]),))
|
|
instruction_diagram(((12, [imm[12:23]]),), ((12, [ımm[24:35]]),), voff: -3)
|
|
instruction_diagram(((12, [imm[36:47]]),), voff: -6)
|
|
},
|
|
),
|
|
)
|
|
|
|
#let aslr = [Actió Sequentiae Loci Recordandí]
|
|
== #aslr
|
|
|
|
#align(center, cetz.canvas({
|
|
cetz.draw.scale(.65)
|
|
instruction_diagram((
|
|
(1, [1]),
|
|
(1, [0]),
|
|
(1, [1]),
|
|
(4, [r#sub[a]]),
|
|
(1, [I]),
|
|
(1, [C]),
|
|
(1, [N]),
|
|
(1, [Z]),
|
|
(1, [R]),
|
|
))
|
|
}))
|
|
|
|
#let asrd = [Actió Sequentiae Recordandó Dépositus]
|
|
== #asrd
|
|
|
|
#align(center, cetz.canvas({
|
|
cetz.draw.scale(.65)
|
|
instruction_diagram((
|
|
(1, [1]),
|
|
(1, [1]),
|
|
(1, [0]),
|
|
(4, [r#sub[a]]),
|
|
(1, [I]),
|
|
(1, [C]),
|
|
(1, [N]),
|
|
(1, [Z]),
|
|
(1, [R]),
|
|
), ((12, [imm[0:11]]),))
|
|
}))
|
|
|
|
#pagebreak(weak: true)
|
|
= Instructions by their mnemonics
|
|
|
|
Common Notations:
|
|
/ ```ain48 %a, %b, %c, ...```: any register a, b, c
|
|
/ ```ain48 #imm[n]```: An immediate (max: n bits)
|
|
/ ```ain48 %0, %nul```: Writes to ```ain48 %0 / %nul``` are discarded
|
|
/ ```ain48 (%a)```: The memory at the adress contained by %a
|
|
/ ```ain48 (#imm[n])```: The memory at the adress represented by the immediate (max n bits)
|
|
/ ```ain48 a_label```: The memory adress correspoding to the label
|
|
|
|
#let ristr(mnem) = [*#raw(mnem, lang: "ain48")* (#ref(label("ins:" + mnem), form: "page"))]
|
|
#let istr(mnem) = strong(raw(mnem, lang: "ain48"))
|
|
#let opt(a, b) = box[
|
|
*#a* = #b
|
|
]
|
|
#let optgrid(..opts) = block({
|
|
text(weight: 900)[Instruction parameters]
|
|
linebreak()
|
|
h(1em)
|
|
opts.pos().join(h(2em))
|
|
})
|
|
#let aludoc(mnemonic, opnum, opsym, commutative, s) = [
|
|
#optgrid(opt[op][#opnum], opt[s][#s])
|
|
/ Instruction format: #amal
|
|
/ #raw(mnemonic + " %a, %b, %c", lang: "ain48"): %a ← %b #opsym %c
|
|
#optgrid(
|
|
opt[i#sub[1]][0],
|
|
opt[i#sub[2]][0],
|
|
opt[r#sub[d]][a],
|
|
opt[r#sub[1]][b],
|
|
opt[r#sub[2]][c],
|
|
)
|
|
/ #raw(mnemonic + " %a, %b, #imm[4]", lang: "ain48"): %a ← %b #opsym imm
|
|
#optgrid(
|
|
opt[i#sub[1]][0],
|
|
opt[i#sub[2]][1],
|
|
opt[r#sub[d]][a],
|
|
opt[r#sub[1]][b],
|
|
opt[imm][imm],
|
|
)
|
|
#if not commutative [
|
|
/ #raw(mnemonic + " %a, #imm[4], %b", lang: "ain48"): %a ← imm #opsym %b
|
|
#optgrid(
|
|
opt[i#sub[1]][1],
|
|
opt[i#sub[2]][0],
|
|
opt[r#sub[d]][a],
|
|
opt[r#sub[2]][b],
|
|
opt[imm][imm],
|
|
)
|
|
]
|
|
/ #raw(mnemonic + " %a, #imm[8]", lang: "ain48"): %a ← %a #opsym imm
|
|
#optgrid(opt[i#sub[1]][1], opt[i#sub[2]][1], opt[r#sub[d]][a], opt[imm][imm])
|
|
|
|
]
|
|
#let instructions = (
|
|
(mnem: "STR", name: "Subtrahere", sign: true, description: [
|
|
Subtract one signed number from another
|
|
#aludoc("STR", "01", "-", false, 1)
|
|
]),
|
|
(mnem: "ADD", name: "Addere", sign: true, description: [
|
|
Add two signed numbers together.
|
|
#aludoc("ADD", "00", "+", true, 1)
|
|
]),
|
|
(mnem: "MPL", name: "Multiplicáre", sign: true, description: [
|
|
Multiply two signed numbers together
|
|
#aludoc("MPL", "02", "×", true, 1)
|
|
/ Instruction format: #amal
|
|
]),
|
|
(mnem: "RSD", name: "Residérí", sign: true, description: [
|
|
Reminder of the euclidian division of two words
|
|
#aludoc("RSD", "05", "mod", false, 1)
|
|
]),
|
|
(mnem: "DVD", name: "Dívidere", sign: true, description: [
|
|
Divide a signed number by another
|
|
#aludoc("DVD", "04", "/", false, 1)
|
|
]),
|
|
(mnem: "DEM", name: "Ad Dextró Movére", sign: true, description: [
|
|
Shift a signed number left by a signed number.
|
|
#aludoc("DEM", "06", ">>", false, 1)
|
|
]),
|
|
(mnem: "SIM", name: "Ad Sinistró Movére", description: [
|
|
Shift a word to the left
|
|
#aludoc("SIM", "07", "<<", false, 0)
|
|
]),
|
|
(
|
|
mnem: "ILG",
|
|
name: "Immediátum Legere",
|
|
sign: true,
|
|
description: [
|
|
Load a signed immediate value into a register
|
|
/ ```ain48 ILG %a, #imm[12]```: %a ← imm
|
|
/ Instruction format: #ipl
|
|
#optgrid(opt[s][1], opt[r][a], opt[imm][imm])
|
|
/ ```ain48 ILG %a, #imm[48]```: %a ← imm
|
|
/ Instruction format: #iml
|
|
#optgrid(opt[s][1], opt[r][a], opt[imm][imm])
|
|
The assembler has freedom to choose the appropriate format given the size of the
|
|
immediate. The mnemonics #ristr("IMLG") and #ristr("IPLG") also exist to allow
|
|
the programmer to explicitely request one format or the other: #istr("IMLG") uses #iml and
|
|
#istr("IPLG") uses #ipl.
|
|
],
|
|
also: (
|
|
("IPLG", "Immediátum Parvum Legere"),
|
|
("IMLG", "Immediátum Magnum Legere"),
|
|
),
|
|
),
|
|
(
|
|
mnem: "I",
|
|
name: "Íre",
|
|
description: [
|
|
Go to
|
|
/ ```ain48 I a_label```: %ia ← a_label
|
|
/ Instruction Format: #asli
|
|
#optgrid(
|
|
opt[I][1],
|
|
opt[C][0],
|
|
opt[N][0],
|
|
opt[Z][0],
|
|
opt[R][0],
|
|
opt[imm][a_label],
|
|
)
|
|
Some assemblers may opt to assemble calls to nearby labels as if they were of
|
|
the form `IRE %0, #imm[12]` with no loss of correctness.
|
|
/ ```ain48 I #imm[48]```: %ia ← imm\
|
|
/ Instruction Format: #asli
|
|
#optgrid(
|
|
opt[I][1],
|
|
opt[C][0],
|
|
opt[N][0],
|
|
opt[Z][0],
|
|
opt[R][0],
|
|
opt[imm][a_label],
|
|
)
|
|
/ ```ain48 I %a```: %ia ← %a\
|
|
/ Instruction Format: #aslr
|
|
#optgrid(
|
|
opt[I][1],
|
|
opt[C][0],
|
|
opt[N][0],
|
|
opt[Z][0],
|
|
opt[R][0],
|
|
opt[r#sub[a]][a],
|
|
)
|
|
/ ```ain48 I %nul, #imm[12]```: %ia ← %ia + %a
|
|
/ Instruction Format: #asrd
|
|
#optgrid(
|
|
opt[I][1],
|
|
opt[C][0],
|
|
opt[N][0],
|
|
opt[Z][0],
|
|
opt[R][0],
|
|
opt[r#sub[a]][0],
|
|
opt[imm][imm],
|
|
)
|
|
This is a special case of the format just below, where becasue offsetting from
|
|
%nul is useless, we instead understand it as an offset from %ia
|
|
/ ```ain48 I %a, #imm[12]```: %ia ← %a + imm
|
|
/ Instruction Format: #asrd
|
|
#optgrid(
|
|
opt[I][1],
|
|
opt[C][0],
|
|
opt[N][0],
|
|
opt[Z][0],
|
|
opt[R][0],
|
|
opt[r#sub[a]][a],
|
|
opt[imm][imm],
|
|
)
|
|
|
|
],
|
|
also: (
|
|
(
|
|
"UI",
|
|
"Si nullus est íre",
|
|
[
|
|
Used like #istr("I") but only jump if the zero bit of the staus flag is set.\
|
|
#optgrid(opt[I][0], opt[Z][1])
|
|
],
|
|
),
|
|
(
|
|
"NUI",
|
|
"Si nón nullus est íre",
|
|
[
|
|
Used like #istr("I") but only jump if the zero bit of the status flag is not set.\
|
|
#optgrid(opt[I][1], opt[Z][1])
|
|
],
|
|
),
|
|
(
|
|
"NI",
|
|
"Si negatívus est íre",
|
|
[
|
|
Used like #istr("I") but only jump if the negative bit of the status flag is set.\
|
|
#optgrid(opt[I][0], opt[N][1])
|
|
],
|
|
),
|
|
(
|
|
"NNI",
|
|
"Si nón negatívus est íre",
|
|
[
|
|
Used like #istr("I") but only jump if the negative bit of the status flag is not set.\
|
|
#optgrid(opt[I][1], opt[N][1])
|
|
],
|
|
),
|
|
(
|
|
"EI",
|
|
"Si excedit íre",
|
|
[
|
|
Used like #istr("I") but only jump if the carry bit of the status flag is set.\
|
|
#optgrid(opt[I][0], opt[C][1])
|
|
],
|
|
),
|
|
(
|
|
"NEI",
|
|
"Si nón excedit íre",
|
|
[
|
|
Used like #istr("I") but only jump if the carry bit of the status flag is not set.\
|
|
#optgrid(opt[I][1], opt[C][1])
|
|
],
|
|
),
|
|
(
|
|
"PI",
|
|
"Si positívus est íre",
|
|
[
|
|
Used like #istr("I") but only jump if neither the zero nor negative flags of the status
|
|
flag is set.
|
|
#optgrid(opt[I][1], opt[N][1], opt[Z][1])
|
|
],
|
|
),
|
|
(
|
|
"NPI",
|
|
"Si nón positívus est íre",
|
|
[
|
|
Used like #istr("I") but only jump if either the zero or negative flags of the status
|
|
flag are set.
|
|
#optgrid(opt[I][0], opt[N][1], opt[Z][1])
|
|
],
|
|
),
|
|
("IVC", "Invocáre", [
|
|
Used like #istr("I") but sets up a function environment prior to jumping:\
|
|
(%it) ← %ia; %it ← %it - 4
|
|
|
|
#optgrid(opt[R][1])
|
|
],),
|
|
),
|
|
),
|
|
(
|
|
mnem: "NCIVC",
|
|
name: "In Nucleó Invocáre",
|
|
description: [
|
|
Invoke a kernel space function, see your operating system's ABI for more
|
|
details.
|
|
/ Instruction format: #asss
|
|
#optgrid(opt[op][3])
|
|
/ ```ain48 NCIVC```: Perform a kernel call.
|
|
],
|
|
),
|
|
(mnem: "IRRV", name: "De Interruptó Reveníre", description: [
|
|
*Priviledged*
|
|
Instrucion used to exit from the interrupt handler.
|
|
#optgrid(opt[op][4])
|
|
]),
|
|
(mnem: "NCRV", name: "De Nucleó Reveníre", description: [
|
|
*Priviledged*
|
|
Return to user space after a system call
|
|
/ Instruction Format: #asss
|
|
#optgrid(opt[op][2])
|
|
]),
|
|
(mnem: "VEL", name: "Vel", description: [
|
|
Bitwise disjunction between two words
|
|
#aludoc("VEL", [11], sym.or, true, 0)
|
|
]),
|
|
(mnem: "NEC", name: "Nec", description: [
|
|
Bitwise negated disjunction between two words
|
|
#aludoc("NEC", [15], sym.not + sym.or, true, 0)
|
|
]),
|
|
(mnem: "AUT", name: "Aut", description: [
|
|
Bitwise difference between two numbers.
|
|
#aludoc("AUT", [12], sym.xor, true, 0)
|
|
]),
|
|
(mnem: "AEQ", name: "Aequí", description: [
|
|
Bitwise equality between two numbers.
|
|
#aludoc("AEQ", [16], [=], true, 0)
|
|
]),
|
|
(mnem: "ET", name: "Et", description: [
|
|
Bitwise logical conjunction between two numbers.
|
|
#aludoc("ET", [10], sym.and, true, 0)
|
|
]),
|
|
(mnem: "NAM", name: "Non ambó", description: [
|
|
Bitwise negated logical conjunction between two numbers.
|
|
#aludoc("NAM", [14], sym.not + sym.and, true, 0)
|
|
]),
|
|
(
|
|
mnem: "LG",
|
|
name: "Legere",
|
|
description: [
|
|
Read a word from memory
|
|
/ Instruction Format: #amls
|
|
/ ```ain48 LG %a, (%b), #imm[12]```: %a ← (%b + imm)
|
|
#optgrid(opt[w][0], opt[r#sub[d]][a], opt[r#sub[a]][b], opt[imm][imm])
|
|
/ ```ain48 LG %a, (%b)```: This is a special case of ```ain48 LG %a, (%b), #imm[12]``` where imm = 0
|
|
],
|
|
),
|
|
(
|
|
mnem: "SC",
|
|
name: "Scríbere",
|
|
description: [
|
|
Write a word to memory
|
|
/ Instruction Format: #amls
|
|
/ ```ain48 SC %a, (%b), #imm[12]```: (%b + imm) ← %a
|
|
#optgrid(opt[w][1], opt[r#sub[d]][a], opt[r#sub[a]][b], opt[imm][imm])
|
|
/ ```ain48 SC %a, (%b)```: This is a special case of ```ain48 SC %a, (%b), #imm[12]``` where imm = 0
|
|
],
|
|
),
|
|
(mnem: "CESS", name: "Cessáre", description: [
|
|
Halts Execution of the process
|
|
/ Instruction Format: #asss
|
|
#optgrid(opt[op][7])
|
|
/ ```ain48 CESS```: Pause execution.
|
|
]),
|
|
(mnem: "RV", name: "Reveníre", description: [
|
|
Returns from a subroutine.
|
|
/ Instruction Format: #asss
|
|
#optgrid(opt[op][0])
|
|
/ ```ain48 RV```: %it ← %it - 4; %ia ← (%it)
|
|
]),
|
|
(mnem: "CST", name: "Construere", description: [
|
|
Push the contents of a register onto the stack:
|
|
/ ```ain48 CST %a```: This instruction is a macro implemented as follows:\
|
|
#raw(block: true, "SC %a, (%it)\nPSTR %it, #4", lang: "ain48")
|
|
]),
|
|
(mnem: "DST", name: "Destruere", description: [
|
|
Push the contents of a register onto the stack:
|
|
/ ```ain48 DST %a```: This instruction is a macro implemented as follows:\
|
|
#raw(block: true, "PADD %it, #4\nLG %a, (%it)", lang: "ain48")
|
|
]),
|
|
(mnem: "TSC", name: "Transcríbere", description: [
|
|
Copy between registers
|
|
/ ```ain48 TSC %a, %b```: %a ← %b. Macro for ```ain48 VEL %a, %b, %nul```
|
|
]
|
|
),
|
|
)
|
|
|
|
#instructions.map(
|
|
it => {
|
|
let arr = ((mnem: it.mnem, desc: block(breakable: false, width: 100%)[
|
|
== #it.mnem | #it.name
|
|
#label("ins:" + it.mnem)
|
|
#it.description
|
|
|
|
#if it.keys().contains("sign") [See also #ristr("P" + it.mnem)]
|
|
]),)
|
|
if it.keys().contains("sign") {
|
|
arr.push((mnem: "P" + it.mnem, desc: [
|
|
== P#(it.mnem) | Positívós #it.name
|
|
#label("ins:P" + it.mnem)
|
|
Same form(s) as #istr(it.mnem) but with s = 0\
|
|
Unsigned version of #ristr(it.mnem)
|
|
]))
|
|
}
|
|
if it.keys().contains("also") {
|
|
for (m, n, ..r) in it.also {
|
|
arr.push((mnem: m, desc: [
|
|
== #m | #n
|
|
#label("ins:" + m)
|
|
#r.join()
|
|
|
|
See #ristr(it.mnem)
|
|
|
|
]))
|
|
if it.keys().contains("sign") {
|
|
arr.push(
|
|
(
|
|
mnem: "P" + m,
|
|
desc: [
|
|
== P#m | Positivós #n
|
|
Unsigned version of #m, see #ristr("P" + it.mnem) and #ristr(it.mnem)
|
|
],
|
|
),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
arr
|
|
},
|
|
).join().sorted(key: it => it.mnem).map(it => it.desc).join()
|
|
|
|
#pagebreak(weak: true)
|
|
#outline(depth: 2)
|