Compare commits
13 Commits
c4dbfc0480
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
2317f1e2b7
|
|||
|
30ff19d7ff
|
|||
|
|
52b743de9a
|
||
|
|
f1ef3d99f1
|
||
|
3515dee802
|
|||
|
91a8633243
|
|||
|
|
6ccbe2fdbf
|
||
|
bd58085d9e
|
|||
|
3e3a39963e
|
|||
|
c8dbbac38f
|
|||
|
|
57d82b7e29
|
||
|
|
905d05624f
|
||
|
dd699cc933
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,5 +1,9 @@
|
||||
/compile_commands.json
|
||||
/compile_flags.txt
|
||||
/build
|
||||
/docs/*.pdf
|
||||
/ain48
|
||||
/scratch
|
||||
/programs/dist-newstyle/
|
||||
|
||||
|
||||
|
||||
62
Makefile
62
Makefile
@ -1,62 +0,0 @@
|
||||
# PROGRAMS
|
||||
CC = clang
|
||||
CXX = clang++
|
||||
LD = clang
|
||||
AR = ar
|
||||
RM = rm -f
|
||||
TYPST = typst
|
||||
|
||||
# COMPILATION FLAGS
|
||||
LIBS = raylib
|
||||
ifdef DEBUG
|
||||
CFLAGS += -Og -g -DDEBUG
|
||||
else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
CFLAGS += -Wall -Wextra -pedantic -std=gnu23 -Iinclude -Werror=return-type $(shell pkg-config --cflags $(LIBS))
|
||||
LDFLAGS += $(shell pkg-config --libs $(LIBS))
|
||||
|
||||
# FILES
|
||||
SRCS=$(wildcard src/*.c)
|
||||
DEPS=$(patsubst src/%.c, build/%.d, $(SRCS))
|
||||
OBJS=$(patsubst src/%.c, build/%.o, $(SRCS))
|
||||
|
||||
DOCSRC=$(wildcard docs/*.typ)
|
||||
DOCS=$(patsubst docs/%.typ, docs/%.pdf, $(DOCSRC))
|
||||
|
||||
PROGRAM=ain48
|
||||
|
||||
.PHONY: all build docs clean deepclean
|
||||
all: build docs
|
||||
|
||||
build: $(PROGRAM)
|
||||
|
||||
docs: $(DOCS)
|
||||
|
||||
docs/%.pdf: docs/%.typ
|
||||
$(TYPST) c $< $@
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS)
|
||||
$(RM) $(DEPS)
|
||||
$(RM) compile_commands.json
|
||||
deepclean: clean
|
||||
$(RM) $(PROGRAM)
|
||||
$(RM) $(DOCS)
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
$(LD) $(LDFLAGS) $(OBJS) -o $@
|
||||
|
||||
build/%.d: src/%.c
|
||||
@mkdir -p $(@D)
|
||||
@set -e ; $(RM) $@; \
|
||||
$(CC) -M $(CFLAGS) $< > $@.$$$$; \
|
||||
sed 's,\($*\)\.o[ :]*,build/\1.o $@ : ,g' < $@.$$$$ > $@; \
|
||||
$(RM) $@.$$$$
|
||||
|
||||
build/%.o: src/%.c
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
include $(DEPS)
|
||||
|
||||
@ -6,14 +6,12 @@
|
||||
set text(
|
||||
font: "Iosevka Etoile",
|
||||
features: (cv47: 10),
|
||||
number-type: "old-style",
|
||||
weight: 400,
|
||||
size: 12pt,
|
||||
)
|
||||
set par(justify: true)
|
||||
set heading(numbering: "I.1")
|
||||
show raw: set text(font: "Iosevka Slab", size: 1em / .8)
|
||||
show math.equation: set text(font: "Fira Math", weight: 400)
|
||||
show title: align.with(center)
|
||||
show strong: text.with(weight: 900)
|
||||
set figure(numbering: "1", placement: auto)
|
||||
@ -27,5 +25,25 @@
|
||||
}))
|
||||
set raw(theme: "./gruvbox-white.tmTheme")
|
||||
show raw.where(lang: "ain48"): set raw(syntaxes: "./ain48.sublime-syntax")
|
||||
show raw.where(lang: "struct"): set raw(syntaxes: "./struct.sublime-syntax")
|
||||
doc
|
||||
}
|
||||
|
||||
#let byte_diag(..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]
|
||||
}
|
||||
}
|
||||
|
||||
17
docs/Makefile
Normal file
17
docs/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
# PROGRAMS
|
||||
RM = rm -f
|
||||
TYPST = typst
|
||||
|
||||
# FILES
|
||||
DOCSRC=$(wildcard *.typ)
|
||||
DOCS=$(DOCSRC:.typ=.pdf)
|
||||
.PHONY: all docs clean
|
||||
all: docs
|
||||
|
||||
docs: $(DOCS)
|
||||
|
||||
%.pdf: %.typ
|
||||
$(TYPST) c $< $@
|
||||
|
||||
clean:
|
||||
$(RM) $(DOCS)
|
||||
@ -6,20 +6,20 @@ file_extensions:
|
||||
scope: source.ain48asm
|
||||
contexts:
|
||||
main:
|
||||
- match: '(?i)\b(ADD|AEQ|AUT|CESS|CST|DEM|DST|DVD|EI|ET|I|ILG|IMLG|IPLG|IRRV|IVC|LG|MPL|NAM|NCIVC|NCRV|NEC|NEI|NI|NNI|NPI|NUI|PADD|PDEM|PDVD|PI|PILG|PIMLG|PIPLG|PMPL|PRSD|PSTR|RSD|RV|SC|SIM|STR|TSC|UI|VEL)\b'
|
||||
- match: '(?i)\b(P?[SBQ]?(ADD|DEM|DVD|MPL|RSD|SIM|STR)|AEQ|AN|AUT|[SBQ]?(LG|SC)|CESS|CST|DST|(N?[ENUP])?I|ET|P?I[MP]?LG|IRRV|(NC)?(IVC|RV)|NAM|NEC|TSC|VEL)\b'
|
||||
scope: keyword.operator.word.ain48
|
||||
- match: '(?i)%([a-z0-7]+)\b'
|
||||
scope: variable.register.ain48
|
||||
- match: '#-?([0-5]+|o[0-7]+|b[01]+|x[0-9]+)\b'
|
||||
- match: '#-?(s[0-5]+|o[0-7]+|b[01]+|x[0-9]+)\b'
|
||||
scope: constant.numeric.ain48
|
||||
- match: '#imm\[[0-9n]+\]'
|
||||
scope: constant.numeric.ain48
|
||||
- match: ';'
|
||||
scope: comment
|
||||
push: comments
|
||||
- match: '^[a-zA-Z0-9_-]+:$'
|
||||
- match: '^[a-zA-Z0-9_-]+:'
|
||||
scope: keyword.control.label.ain48
|
||||
- match: '^.[a-zA-Z]+'
|
||||
- match: '\.[a-zA-Z]+'
|
||||
scope: keyword.directive.ain48
|
||||
comments:
|
||||
- meta_scope: comment
|
||||
|
||||
370
docs/isa.typ
370
docs/isa.typ
@ -11,7 +11,7 @@
|
||||
[Internátionális],
|
||||
[Nórmae],
|
||||
grid.cell(rowspan: 2)[--- 48 bit],
|
||||
[Intstrúctiónum],
|
||||
[Instrúctiónum],
|
||||
[Numerátiónum],
|
||||
))
|
||||
|
||||
@ -24,14 +24,17 @@
|
||||
]
|
||||
= Conventions
|
||||
|
||||
A *byte* (singulus) is the smallest adressable part of memory, that is, a 12-bit
|
||||
A *byte* (singulus) is the smallest addressable part of memory, that is, a 12-bit
|
||||
binary number.
|
||||
|
||||
A *half-word* (binus) is a binary number composed of 2 bytes, that is, a 24 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
|
||||
lowest memory address.
|
||||
|
||||
= Registers
|
||||
The main registers of the architecture are all word-length:
|
||||
@ -62,26 +65,8 @@ There is also a 3-bit status register.
|
||||
|
||||
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.
|
||||
memory address.
|
||||
|
||||
#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
|
||||
@ -92,53 +77,27 @@ memory adress.
|
||||
{
|
||||
import cetz.draw: *
|
||||
scale(.65)
|
||||
instruction_diagram((
|
||||
byte_diag((
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [i#sub[2]\ 0]),
|
||||
(1, [i#sub[1]\ 0]),
|
||||
(2, [m]),
|
||||
(1, [i\ 0]),
|
||||
(1, [s]),
|
||||
(4, [op]),
|
||||
), ((4, [r#sub[d]]), (4, [r#sub[2]]), (4, [r#sub[1]])))
|
||||
(4, [ac]),
|
||||
), ((4, [r#sub[f]]), (4, [r#sub[2]]), (4, [r#sub[1]])))
|
||||
content((12.25, -1))[or]
|
||||
instruction_diagram(voff: -5, (
|
||||
byte_diag(voff: -5, (
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [i#sub[2]\ 0]),
|
||||
(1, [i#sub[1]\ 1]),
|
||||
(2, [m]),
|
||||
(1, [i\ 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]])))
|
||||
(4, [ac]),
|
||||
), ((4, [r#sub[f]]), (8, [imm[0:7]])))
|
||||
},
|
||||
),
|
||||
)
|
||||
@ -152,19 +111,19 @@ memory adress.
|
||||
{
|
||||
import cetz.draw: *
|
||||
scale(.65)
|
||||
instruction_diagram((
|
||||
(1, [0]),
|
||||
byte_diag((
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [1]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [s]),
|
||||
(4, [r]),
|
||||
), ((12, [imm[0:11]]),))
|
||||
instruction_diagram(((12, [imm[12:23]]),), ((12, [imm[24:35]]),), voff: -3)
|
||||
instruction_diagram(((12, [imm[36:47]]),), voff: -6)
|
||||
byte_diag(((12, [imm[12:23]]),), ((12, [imm[24:35]]),), voff: -3)
|
||||
byte_diag(((12, [imm[36:47]]),), voff: -6)
|
||||
},
|
||||
),
|
||||
)
|
||||
@ -175,14 +134,14 @@ memory adress.
|
||||
#align(center, cetz.canvas({
|
||||
import cetz.draw: *
|
||||
scale(.65)
|
||||
instruction_diagram((
|
||||
(1, [0]),
|
||||
byte_diag((
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [1]),
|
||||
(1, [1]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [s]),
|
||||
(4, [r]),
|
||||
), ((12, [imm[0:11]]),))
|
||||
@ -193,13 +152,13 @@ memory adress.
|
||||
#align(center, cetz.canvas({
|
||||
import cetz.draw: *
|
||||
scale(.65)
|
||||
instruction_diagram((
|
||||
(1, [0]),
|
||||
byte_diag((
|
||||
(1, [0]),
|
||||
(1, [1]),
|
||||
(1, [w]),
|
||||
(1, [0]),
|
||||
(1, [s]),
|
||||
(4, [r#sub[d]]),
|
||||
(4, [r#sub[a]]),
|
||||
(4, [r#sub[l]]),
|
||||
), ((12, [imm[0:11]]),))
|
||||
}))
|
||||
|
||||
@ -208,7 +167,7 @@ memory adress.
|
||||
#align(center, cetz.canvas({
|
||||
import cetz.draw: *
|
||||
scale(.65)
|
||||
instruction_diagram((
|
||||
byte_diag((
|
||||
(1, [1]),
|
||||
(1, [1]),
|
||||
(1, [1]),
|
||||
@ -218,7 +177,7 @@ memory adress.
|
||||
(1, [1]),
|
||||
(1, [1]),
|
||||
(1, [1]),
|
||||
(3, [op]),
|
||||
(3, [ac]),
|
||||
))
|
||||
}))
|
||||
|
||||
@ -231,7 +190,7 @@ memory adress.
|
||||
{
|
||||
import cetz.draw: *
|
||||
scale(.65)
|
||||
instruction_diagram((
|
||||
byte_diag((
|
||||
(1, [1]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
@ -239,14 +198,14 @@ memory adress.
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [0]),
|
||||
(1, [I]),
|
||||
(1, [C]),
|
||||
(1, [E]),
|
||||
(1, [N]),
|
||||
(1, [Z]),
|
||||
(1, [U]),
|
||||
(1, [R]),
|
||||
), ((12, [imm[0:11]]),))
|
||||
instruction_diagram(((12, [imm[12:23]]),), ((12, [imm[24:35]]),), voff: -3)
|
||||
instruction_diagram(((12, [imm[36:47]]),), voff: -6)
|
||||
byte_diag(((12, [imm[12:23]]),), ((12, [imm[24:35]]),), voff: -3)
|
||||
byte_diag(((12, [imm[36:47]]),), voff: -6)
|
||||
},
|
||||
),
|
||||
)
|
||||
@ -256,15 +215,15 @@ memory adress.
|
||||
|
||||
#align(center, cetz.canvas({
|
||||
cetz.draw.scale(.65)
|
||||
instruction_diagram((
|
||||
byte_diag((
|
||||
(1, [1]),
|
||||
(1, [0]),
|
||||
(1, [1]),
|
||||
(4, [r#sub[a]]),
|
||||
(4, [r#sub[l]]),
|
||||
(1, [I]),
|
||||
(1, [C]),
|
||||
(1, [E]),
|
||||
(1, [N]),
|
||||
(1, [Z]),
|
||||
(1, [U]),
|
||||
(1, [R]),
|
||||
))
|
||||
}))
|
||||
@ -274,15 +233,15 @@ memory adress.
|
||||
|
||||
#align(center, cetz.canvas({
|
||||
cetz.draw.scale(.65)
|
||||
instruction_diagram((
|
||||
byte_diag((
|
||||
(1, [1]),
|
||||
(1, [1]),
|
||||
(1, [0]),
|
||||
(4, [r#sub[a]]),
|
||||
(4, [r#sub[l]]),
|
||||
(1, [I]),
|
||||
(1, [C]),
|
||||
(1, [E]),
|
||||
(1, [N]),
|
||||
(1, [Z]),
|
||||
(1, [U]),
|
||||
(1, [R]),
|
||||
), ((12, [imm[0:11]]),))
|
||||
}))
|
||||
@ -294,9 +253,9 @@ 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
|
||||
/ ```ain48 (%a)```: The memory at the address contained by %a
|
||||
/ ```ain48 (#imm[n])```: The memory at the address represented by the immediate (max n bits)
|
||||
/ ```ain48 a_label```: The memory address corresponding to the label
|
||||
|
||||
#let ristr(mnem) = [*#raw(mnem, lang: "ain48")* (#ref(label("ins:" + mnem), form: "page"))]
|
||||
#let istr(mnem) = strong(raw(mnem, lang: "ain48"))
|
||||
@ -309,75 +268,71 @@ Common Notations:
|
||||
h(1em)
|
||||
opts.pos().join(h(2em))
|
||||
})
|
||||
#let aludoc(mnemonic, opnum, opsym, commutative, s) = [
|
||||
#optgrid(opt[op][#opnum], opt[s][#s])
|
||||
#let aludoc(mnemonic, opnum, opsym, s) = [
|
||||
#optgrid(opt[op][#opnum], opt[s][#s], opt[w][2])
|
||||
/ 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[i][0],
|
||||
opt[r#sub[f]][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])
|
||||
#optgrid(opt[i][1], opt[r#sub[f]][a], opt[imm][imm])
|
||||
|
||||
]
|
||||
#let sized_also(mnem, name) = (also: (
|
||||
( "S" + mnem, "Singulum " + name, [Same as #istr(mnem), but operates on bytes #optgrid(opt[w][0])]),
|
||||
( "B" + mnem, "Binum " + name, [Same as #istr(mnem), but operates on half-words #optgrid(opt[w][1])]),
|
||||
( "Q" + mnem, "Quaternum " + name, [Alias for the unsized version, operates on words]),
|
||||
))
|
||||
#let instructions = (
|
||||
(mnem: "STR", name: "Subtrahere", sign: true, description: [
|
||||
Subtract one signed number from another
|
||||
#aludoc("STR", "01", "-", false, 1)
|
||||
]),
|
||||
Subtract one signed number from another.
|
||||
#aludoc("STR", "01", "-", 1)
|
||||
/ Instruction format: #amal
|
||||
], ..sized_also("STR", "Subtrahere")),
|
||||
(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)
|
||||
#aludoc("ADD", "00", "+", 1)
|
||||
/ Instruction format: #amal
|
||||
]),
|
||||
], ..sized_also("ADD", "Addere")),
|
||||
(mnem: "MPL", name: "Multiplicáre", sign: true, description: [
|
||||
Multiply two signed numbers together.
|
||||
#aludoc("MPL", "02", "×", 1)
|
||||
/ Instruction format: #amal
|
||||
], ..sized_also("MPL", "Multiplicáre")),
|
||||
(mnem: "RSD", name: "Residérí", sign: true, description: [
|
||||
Reminder of the euclidian division of two words
|
||||
#aludoc("RSD", "05", "mod", false, 1)
|
||||
]),
|
||||
Remainder of the Euclidean division of two signed integers.
|
||||
Will raise an arithmetic exception if the right operand is zero.
|
||||
#aludoc("RSD", "05", "mod", 1)
|
||||
/ Instruction format: #amal
|
||||
], ..sized_also("RSD", "Residérí")),
|
||||
(mnem: "DVD", name: "Dívidere", sign: true, description: [
|
||||
Divide a signed number by another
|
||||
#aludoc("DVD", "04", "/", false, 1)
|
||||
]),
|
||||
Integer part of the Euclidean division of two signed integers.
|
||||
Will raise an arithmetic exception if the right operand is zero.
|
||||
#aludoc("DVD", "04", "/", 1)
|
||||
/ Instruction format: #amal
|
||||
], ..sized_also("DVD", "Dívidere")),
|
||||
(mnem: "DEM", name: "Ad Dextró Movére", sign: true, description: [
|
||||
Shift a signed number left by a signed number.
|
||||
#aludoc("DEM", "06", ">>", false, 1)
|
||||
]),
|
||||
Shift a signed number right by a signed number.
|
||||
Will raise an arithmetic exception if the right operand is negative.
|
||||
#aludoc("DEM", "06", ">>", 1)
|
||||
/ Instruction format: #amal
|
||||
], ..sized_also("DEM", "Ad Dextró Movére")),
|
||||
(mnem: "SIM", name: "Ad Sinistró Movére", description: [
|
||||
Shift a word to the left
|
||||
#aludoc("SIM", "07", "<<", false, 0)
|
||||
]),
|
||||
Shift a word to the left.
|
||||
Will raise an arithmetic exception if the right operand is negative.
|
||||
#aludoc("SIM", "07", "<<", 0)
|
||||
/ Instruction format: #amal
|
||||
], ..sized_also("SIM", "Ad Sinistró Movére")),
|
||||
(
|
||||
mnem: "ILG",
|
||||
name: "Immediátum Legere",
|
||||
sign: true,
|
||||
description: [
|
||||
Load a signed immediate value into a register
|
||||
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])
|
||||
@ -386,7 +341,7 @@ Common Notations:
|
||||
#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
|
||||
the programmer to explicitly request one format or the other: #istr("IMLG") uses #iml and
|
||||
#istr("IPLG") uses #ipl.
|
||||
],
|
||||
also: (
|
||||
@ -398,15 +353,10 @@ Common Notations:
|
||||
mnem: "I",
|
||||
name: "Íre",
|
||||
description: [
|
||||
Go to
|
||||
Go to (jump to) an instruction other than the one immediately following this instruction.
|
||||
/ ```ain48 I a_label```: %ia ← a_label
|
||||
/ Instruction Format: #asli
|
||||
/ 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
|
||||
@ -414,44 +364,24 @@ Common Notations:
|
||||
/ ```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
|
||||
This is a special case of the format just below, where because offsetting from
|
||||
%nul is useless, we instead interpret 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],
|
||||
)
|
||||
@ -462,23 +392,23 @@ Common Notations:
|
||||
"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])
|
||||
Used like #istr("I"), but only jump if the zero bit of the status flag is set.\
|
||||
#optgrid(opt[I][0], opt[U][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])
|
||||
Used like #istr("I"), but only jump if the zero bit of the status flag is not set.\
|
||||
#optgrid(opt[I][1], opt[U][1])
|
||||
],
|
||||
),
|
||||
(
|
||||
"NI",
|
||||
"Si negatívus est íre",
|
||||
[
|
||||
Used like #istr("I") but only jump if the negative bit of the status flag is set.\
|
||||
Used like #istr("I"), but only jump if the negative bit of the status flag is set.\
|
||||
#optgrid(opt[I][0], opt[N][1])
|
||||
],
|
||||
),
|
||||
@ -486,7 +416,7 @@ Common Notations:
|
||||
"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.\
|
||||
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])
|
||||
],
|
||||
),
|
||||
@ -494,15 +424,15 @@ Common Notations:
|
||||
"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])
|
||||
Used like #istr("I"), but only jump if the carry bit of the status flag is set.\
|
||||
#optgrid(opt[I][0], opt[E][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.\
|
||||
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])
|
||||
],
|
||||
),
|
||||
@ -510,22 +440,22 @@ Common Notations:
|
||||
"PI",
|
||||
"Si positívus est íre",
|
||||
[
|
||||
Used like #istr("I") but only jump if neither the zero nor negative flags of the status
|
||||
Used like #istr("I"), but only jump if neither the zero nor negative flag of the status
|
||||
flag is set.
|
||||
#optgrid(opt[I][1], opt[N][1], opt[Z][1])
|
||||
#optgrid(opt[I][1], opt[N][1], opt[U][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])
|
||||
Used like #istr("I"), but only jump if either the zero or negative flag of the status
|
||||
flag is set.
|
||||
#optgrid(opt[I][0], opt[N][1], opt[U][1])
|
||||
],
|
||||
),
|
||||
("IVC", "Invocáre", [
|
||||
Used like #istr("I") but sets up a function environment prior to jumping:\
|
||||
Used like #istr("I"), but sets up a function environment prior to jumping:\
|
||||
(%it) ← %ia; %it ← %it - 4
|
||||
|
||||
#optgrid(opt[R][1])
|
||||
@ -539,94 +469,104 @@ Common Notations:
|
||||
Invoke a kernel space function, see your operating system's ABI for more
|
||||
details.
|
||||
/ Instruction format: #asss
|
||||
#optgrid(opt[op][3])
|
||||
#optgrid(opt[ac][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])
|
||||
*Privileged*
|
||||
Instruction used to exit from the interrupt handler.
|
||||
/ Instruction format: #asss
|
||||
#optgrid(opt[ac][4])
|
||||
/ ```ain48 IRRV```: Return from an interrupt.
|
||||
]),
|
||||
(mnem: "NCRV", name: "De Nucleó Reveníre", description: [
|
||||
*Priviledged*
|
||||
Return to user space after a system call
|
||||
*Privileged*
|
||||
Return to user space after a system call.
|
||||
/ Instruction Format: #asss
|
||||
#optgrid(opt[op][2])
|
||||
#optgrid(opt[ac][2])
|
||||
/ ```ain48 IRRV```: Return from kernelspace.
|
||||
]),
|
||||
(mnem: "VEL", name: "Vel", description: [
|
||||
Bitwise disjunction between two words
|
||||
#aludoc("VEL", [11], sym.or, true, 0)
|
||||
Bitwise disjunction between two words.
|
||||
#aludoc("VEL", [11], sym.or, 0)
|
||||
]),
|
||||
(mnem: "NEC", name: "Nec", description: [
|
||||
Bitwise negated disjunction between two words
|
||||
#aludoc("NEC", [15], sym.not + sym.or, true, 0)
|
||||
#aludoc("NEC", [15], sym.not + sym.or, 0)
|
||||
]),
|
||||
(mnem: "AUT", name: "Aut", description: [
|
||||
Bitwise difference between two numbers.
|
||||
#aludoc("AUT", [12], sym.xor, true, 0)
|
||||
#aludoc("AUT", [12], sym.xor, 0)
|
||||
]),
|
||||
(mnem: "AEQ", name: "Aequí", description: [
|
||||
Bitwise equality between two numbers.
|
||||
#aludoc("AEQ", [16], [=], true, 0)
|
||||
#aludoc("AEQ", [16], [=], 0)
|
||||
]),
|
||||
(mnem: "ET", name: "Et", description: [
|
||||
Bitwise logical conjunction between two numbers.
|
||||
#aludoc("ET", [10], sym.and, true, 0)
|
||||
#aludoc("ET", [10], sym.and, 0)
|
||||
]),
|
||||
(mnem: "NAM", name: "Non ambó", description: [
|
||||
Bitwise negated logical conjunction between two numbers.
|
||||
#aludoc("NAM", [14], sym.not + sym.and, true, 0)
|
||||
#aludoc("NAM", [14], sym.not + sym.and, 0)
|
||||
]),
|
||||
(
|
||||
mnem: "LG",
|
||||
name: "Legere",
|
||||
description: [
|
||||
Read a word from memory
|
||||
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
|
||||
#optgrid(opt[s][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.
|
||||
],
|
||||
),
|
||||
..sized_also("LG", "Legere"),
|
||||
),
|
||||
(
|
||||
mnem: "SC",
|
||||
name: "Scríbere",
|
||||
description: [
|
||||
Write a word to memory
|
||||
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])
|
||||
#optgrid(opt[s][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
|
||||
],
|
||||
..sized_also("SC", "Scríbere")
|
||||
),
|
||||
(mnem: "CESS", name: "Cessáre", description: [
|
||||
Halts Execution of the process
|
||||
*Privileged* Halts the CPU.
|
||||
/ Instruction Format: #asss
|
||||
#optgrid(opt[op][7])
|
||||
#optgrid(opt[ac][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)
|
||||
Returns from a subroutine.
|
||||
/ Instruction Format: #asss
|
||||
#optgrid(opt[ac][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")
|
||||
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")
|
||||
Pop the contents of the top of the stack into a register.
|
||||
/ ```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```
|
||||
]
|
||||
),
|
||||
Copy between registers.
|
||||
/ ```ain48 TSC %a, %b```: %a ← %b.
|
||||
This instruction is a macro implemented as ```ain48 VEL %a, %b, %nul```.
|
||||
]),
|
||||
(mnem: "AN", name: "Actió Nulla", description: [
|
||||
Do nothing except increment the instruction counter.
|
||||
/ ```ain48 AN```: Do nothing.
|
||||
This instruction is a macro implemented as ```ain48 IPLG %0, #0```.
|
||||
]),
|
||||
)
|
||||
|
||||
#instructions.map(
|
||||
@ -643,7 +583,7 @@ Common Notations:
|
||||
== 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)
|
||||
Unsigned version of #ristr(it.mnem).
|
||||
]))
|
||||
}
|
||||
if it.keys().contains("also") {
|
||||
@ -662,7 +602,7 @@ Common Notations:
|
||||
mnem: "P" + m,
|
||||
desc: [
|
||||
== P#m | Positivós #n
|
||||
Unsigned version of #m, see #ristr("P" + it.mnem) and #ristr(it.mnem)
|
||||
Unsigned version of #istr(m); see #ristr("P" + it.mnem) and #ristr(it.mnem).
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
17
docs/struct.sublime-syntax
Normal file
17
docs/struct.sublime-syntax
Normal file
@ -0,0 +1,17 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
name: struct
|
||||
file_extensions:
|
||||
- struct
|
||||
scope: source.struct
|
||||
contexts:
|
||||
main:
|
||||
- match: '(?i)\b(byte|hword|word|bit)\b'
|
||||
scope: storage.type.struct
|
||||
- match: '\b[0-9_]+\b'
|
||||
scope: constant.numeric.struct
|
||||
- match: '\b(struct|enum|union|flags)\s+[a-zA-Z0-9_]+\b'
|
||||
scope: storage.type.struct
|
||||
- match: '%.*$'
|
||||
scope: comment
|
||||
|
||||
@ -1,34 +1,298 @@
|
||||
#import ".template.typ": *
|
||||
#show: conf
|
||||
|
||||
#show regex("[\u{e3e0}-\u{e3ff}]+(\s+[\u{e3e0-\u{e3ff}]+)*"): text.with(
|
||||
font: "AndikaAmbNaran",
|
||||
)
|
||||
#show raw.where(block: true): block.with(breakable: false)
|
||||
|
||||
#title[Unichal Software Distribution System ABI\ Version 3.4 for AIN-48]
|
||||
© University of Chalmosique, Cross. 301 -- Cross. 319
|
||||
|
||||
= Object Format
|
||||
b
|
||||
= The RIM file format
|
||||
The RIM#footnote[
|
||||
--- Rainsihen Iehanac Móscirts --- Computer
|
||||
Instruction Format
|
||||
] format is the format used by UCSD to encode machine code object files and executables.
|
||||
It is defined as follows.
|
||||
All numbers bigger than a byte are represented in little-endian.
|
||||
The sizes of the types are as follows:
|
||||
/ ```struct byte```: 12 bits
|
||||
/ ```struct hword```: 24 bits, or 2 bytes
|
||||
/ ```struct word```: 48 bits, or 4 bytes
|
||||
All numbers are unsigned.
|
||||
|
||||
= Integer representation
|
||||
= Calling convention
|
||||
== Parameter passing
|
||||
== Return value passing
|
||||
== Call Sequence
|
||||
== RIM Header
|
||||
Placed at the start of the file, it identifies the file as a RIM object and contains some additional flags.
|
||||
|
||||
```ain48
|
||||
.at #o00000000
|
||||
fib_n:
|
||||
ilg %2, #0
|
||||
ilg %3, #1
|
||||
__loop:
|
||||
padd %4, %3, %2
|
||||
tsc %2, %3
|
||||
tsc %3, %3
|
||||
pstr %1, #1
|
||||
nui __loop
|
||||
|
||||
tsc %1, %2
|
||||
rv
|
||||
```struct
|
||||
enum PLATFORM as hword:
|
||||
UCSD-at12 = 00000000
|
||||
UCSD-ain24 = 00000001
|
||||
UCSD-ain48 = 00000002
|
||||
% other formats may exist, as defined in their own implementation
|
||||
% of the RIM specification
|
||||
```
|
||||
```struct
|
||||
flags FILETYPE as byte:
|
||||
EXECUTABLE = 0001
|
||||
SHARED = 0002
|
||||
REPOSITIONABLE = 0004
|
||||
```
|
||||
```struct
|
||||
struct RIM_HEADER:
|
||||
byte[4] magic_number = [0206, 0203, 0213, 7777]
|
||||
% \7777 in the old AT12-IM codepage
|
||||
enum PLATFORM platform
|
||||
hword version % For UCSD 3.4: version = 0001
|
||||
flags FILETYPE type
|
||||
word index_address % offset in the file where the section table is
|
||||
```
|
||||
|
||||
adjective
|
||||
== Section Table
|
||||
Placed at the file offset indicated by `index_address` in the header, the section table contains a list of all the sections, their lengths and their offsets into the file.
|
||||
```struct
|
||||
enum SEC_TYPE as byte:
|
||||
RO_DATA = 0 % Data to be copied into non-executable read-only memory
|
||||
CODE = 1 % Data to be copied into executable read-only memory
|
||||
RW_DATA = 2 % Data to be copied into non-executable read-write memory
|
||||
RW_CODE = 3 % Data to be copied into executable read-write memory
|
||||
SYMBOLS_INTERNAL = 4 % Table listing all the linkable symbols of
|
||||
% the object
|
||||
SYMBOLS_EXTERNAL = 5 % Table listing all the symbols the objects needs
|
||||
% to link to to be usable.
|
||||
STRINGS = 6 % Container for all the strings for symbols and debug info
|
||||
DEBUG = 7 % Debug information
|
||||
META = 7777 % Extra Information about the object
|
||||
```
|
||||
```struct
|
||||
struct SEC_TABLE_ENTRY:
|
||||
enum SEC_TYPE type
|
||||
adjective
|
||||
word offset
|
||||
```
|
||||
```struct
|
||||
struct SECTION_TABLE:
|
||||
hword count
|
||||
struct SEC_TABLE_ENTRY[count] entries
|
||||
```
|
||||
|
||||
== Code and Data Sections
|
||||
Sections tagged `RO_DATA`, `CODE`, `RW_DATA` and `RW_CODE` are all encoded the same way.
|
||||
Ideally the start of such a section is to be at an offset that is a multiple of 4 bytes.
|
||||
```struct
|
||||
struct DATA_SECTION:
|
||||
word length % How many bytes of data
|
||||
word req_addr % Where should the data be located in memory. Note
|
||||
% that this field is ignored if the RELOCATABLE flag
|
||||
% is set in the header.
|
||||
byte[length] data
|
||||
```
|
||||
|
||||
== Symbol tables
|
||||
The symbol tables contain data about the linkable symbols of the object.
|
||||
```struct
|
||||
struct SYMBOL_TABLE:
|
||||
hword count
|
||||
struct SYMBOL_TABLE_ENTRY[count] entries
|
||||
```
|
||||
```struct
|
||||
struct SYMBOL_TABLE_ENTRY:
|
||||
% Number of the string section and index into that section
|
||||
% referencing the name of the symbol
|
||||
hword string_section
|
||||
hword string_number
|
||||
% For internal symbol tables: the section and offset referring to the
|
||||
% symbol. For external symbol tables: the section and offset where
|
||||
% the address for that symbol needs to be replaced. If a symbol needs
|
||||
% to be linked between two data sections of the object, have it be
|
||||
% present in both the internal and external tables.
|
||||
hword data_section
|
||||
word data_offset
|
||||
```
|
||||
|
||||
== Strings section
|
||||
```struct
|
||||
struct STRINGS_SECTION:
|
||||
hword count % number of string entries
|
||||
word len % length of the data part
|
||||
word[count] entry_offsets % offsets into `data` of each string
|
||||
byte[len] data % binary data containing the strings
|
||||
```
|
||||
|
||||
== Debug
|
||||
The contents of debug tables is platform-specific.
|
||||
/ TODO: Write the debug info format for UCSD eventually™
|
||||
|
||||
== Meta
|
||||
The meta section contains additional metadata about the file.
|
||||
|
||||
```struct
|
||||
struct META_TABLE:
|
||||
hword count
|
||||
struct META_ENTRY[count] entries
|
||||
```
|
||||
```struct
|
||||
struct META_ENTRY:
|
||||
enum META_ENTRY_TYPE type
|
||||
union META_VALUE val
|
||||
```
|
||||
```struct
|
||||
union META_VALUE: % variant depends on meta entry type
|
||||
struct META_VALUE_STRING string_value
|
||||
word int_value
|
||||
```
|
||||
```struct
|
||||
struct META_VALUE_STRING:
|
||||
hword section % strings section number
|
||||
hword id % entry in string section
|
||||
```
|
||||
```struct
|
||||
enum META_ENTRY_TYPE as hword:
|
||||
ENTRY_POINT = 0 % Kind: int_value, only useful when the file is said to
|
||||
% be executable, gives the entry point for the program.
|
||||
DYNAMIC_LINKER = 1 % Kind: string_value, the name of the dynamic linker
|
||||
% in charge of resolving the symbols upon load of
|
||||
% theobject, only useful if the SHARED flag is set.
|
||||
HASH = 2 % Kind: string_value, a hash against which to verify the
|
||||
% integrity of the object file. Supported algorithms depend on
|
||||
% the linker used. The string is of the format
|
||||
% `algorithm:octal-dump-of-hash`
|
||||
|
||||
% META_ENTRY_TYPEs between 1000 0000 and 3777 7777 (inclusive) are
|
||||
% reserved for platform-specific information. Here are the ones for
|
||||
% UCSD 3.4
|
||||
UCSD_APPLICATION_NAME = 1000 0000 % Kind: string_value, user-facing name
|
||||
% of the application
|
||||
UCSD_ICON_DATA_SYM = 1000 0001 % Kind: string_value, name of a symbol
|
||||
% referencing bitmap image data for an
|
||||
% application icon
|
||||
UCSD_ICON_DATA_NAME = 1000 0002 % Kind: string_value, name of a system-
|
||||
% wide icon that may be installed on
|
||||
% the system
|
||||
% Multiple instances of UCSD_ICON_DATA_NAME and UCSD_ICON_DATA_SYM can
|
||||
% be specified, the system will make use of the first one that resolves
|
||||
% to a usable image.
|
||||
|
||||
% META_ENTRY_TYPEs greater or equal to 4000 0000 are reserved for
|
||||
% private use by external tooling and are not specified in this
|
||||
% document
|
||||
```
|
||||
|
||||
= Representation of types
|
||||
|
||||
== Integers
|
||||
#block(
|
||||
breakable: false,
|
||||
)[This ABI defines 6 integer types: `u12`, `u24` and `u48` which are unsigned 12, 24 and 48 bit integers, as well as `i12`, `i24` and `i48` which are signed (by the two's complement method) 12, 24 and 48 bit integers.
|
||||
|
||||
#grid(columns: (1fr, 1fr), row-gutter: .65em)[
|
||||
/ `u12`: Unsigned 12-bit integer
|
||||
/ Storage size: 1 byte
|
||||
/ Alignment: 1 byte
|
||||
][
|
||||
/ `i12`: Signed 12-bit integer
|
||||
/ Storage size: 1 byte
|
||||
/ Alignment: 1 byte
|
||||
][
|
||||
/ `u24`: Unsigned 24-bit integer
|
||||
/ Storage size: 2 bytes
|
||||
/ Alignment: 2 bytes
|
||||
][
|
||||
/ `i24`: Signed 24-bit integer
|
||||
/ Storage size: 2 bytes
|
||||
/ Alignment: 2 bytes
|
||||
][
|
||||
/ `u48`: Unsigned 48-bit integer
|
||||
/ Storage size: 4 bytes
|
||||
/ Alignment: 4 bytes
|
||||
][
|
||||
/ `i48`: Signed 48-bit integer
|
||||
/ Storage size: 4 bytes
|
||||
/ Alignment: 4 bytes
|
||||
]]
|
||||
|
||||
== Booleans
|
||||
Booleans are represented as `u12`s, where 0 is false and any non-zero value (but canonically 7777) is true.
|
||||
|
||||
== Strings
|
||||
Strings are represented by pointers to a `u12`, followed by that number of bytes of data representing the contents of the string.
|
||||
|
||||
|
||||
= Userspace invocation convention
|
||||
== Parameter passing
|
||||
Parameters are expanded to take a full word and are placed in order:
|
||||
#columns(2)[
|
||||
+ in ```ain48 %01```
|
||||
+ in ```ain48 %02```
|
||||
+ in ```ain48 %03```
|
||||
+ in ```ain48 %04```
|
||||
#colbreak()
|
||||
5. in ```ain48 %05```
|
||||
+ in ```ain48 %06```
|
||||
+ in ```ain48 %07```
|
||||
+ pushed on the stack, with the 8#super[th] argument at the lowest address and the last argument at the highest address.
|
||||
]
|
||||
Arguments placed on the stack are placed starting at the word with the address immediately higher to that of the return adress.
|
||||
|
||||
== Return value passing
|
||||
The return value is to be placed in ```ain48 %01```.
|
||||
|
||||
== Clobbering
|
||||
Registers ```ain48 %01```, ```ain48 %02```, ```ain48 %03```, ```ain48 %04```, ```ain48 %05```,
|
||||
```ain48 %06``` and ```ain48 %07``` may freely be clobbered by the invokee. It is the responsability of the invoker to save them if it is desired to keep their value. Registers ```ain48 %10```, ```ain48 %11```, ```ain48 %12```, ```ain48 %13```, ```ain48 %14```, ```ain48 %15```, ```ain48 %16``` and ```ain48 %it``` must be returned to the invoker in the same state they were upon call. It is the responsibility of the invokee to save them if they are needed for other uses.
|
||||
|
||||
== Invocation Sequence
|
||||
+ The invoker pushes all the registers it needs saved to the stack
|
||||
+ The invoker pushes the stack arguments to the stack
|
||||
+ The invoker loads the registers with the register arguments
|
||||
+ The register executes the ```ain48 IVC``` instruction. This pushes the return address to the stack and transfers control flow to the invokee.
|
||||
+ The invokee allocates its local variables on top of the stack.
|
||||
+ The invokee saves any register it needs to prevent the clobbering of.
|
||||
+ The invokee runs its course
|
||||
+ The invokee restores the registers
|
||||
+ The invokee frees its local variables
|
||||
+ The invokee loads its return value into ```ain48 %01```
|
||||
+ The invokee runs the ```ain48 RV``` instruction. This pops the return address off the stack and transfers control flow back to the invoker.
|
||||
+ The invoker frees the stack arguments.
|
||||
+ The invoker restores the registers it pushed
|
||||
|
||||
|
||||
```ain48
|
||||
; An example
|
||||
.init _init
|
||||
.pars data_sl
|
||||
.univ arg8, arg9
|
||||
arg8: .word #o7612
|
||||
arg9: .hword #o5 .byte #o0, #o0, #o0, #o0, #o0
|
||||
.pars actiones
|
||||
.univ _init
|
||||
_init: CST %02 ; 1. Push registers to be saved
|
||||
ILG %02, arg9 ; 2. Push 9th argument
|
||||
CST %02
|
||||
ILG %02, arg8 ; 2. Push 8th argument
|
||||
LG %02, (%02)
|
||||
CST %02
|
||||
ILG %01, #o1 ; 3. Load register arguments
|
||||
...
|
||||
ILG %07, #o7
|
||||
IVC res ; 4. Transfer to the invokee
|
||||
PADD %it, #o10 ; 12. Free the 2 words of stack arguments
|
||||
DST %02 ; 13. Restore the saved register
|
||||
|
||||
res: PSTR %it, #o14 ; 5. Allocate local variables (here 3 words)
|
||||
CST %10 ; 6. Save invoker-safe registers
|
||||
... ; 7. Res does whatever it does
|
||||
DST %10 ; 8. Restore the invoker-safe registers
|
||||
PADD %it, #o14 ; 9. Free the local variables
|
||||
; 10. Assuming that res has already put its
|
||||
; return value in %01
|
||||
RV ; 11. Transfer back to the invoker
|
||||
```
|
||||
|
||||
= Kernel invocation convention
|
||||
Same as userspace invocation, except for the fact that all arguments are shifted by one, and that ```ain48 %01``` is used to hold the kernel invocation number.
|
||||
|
||||
#pagebreak(weak: true)
|
||||
#outline(depth: 2)
|
||||
|
||||
55
editors/kak/a48s.kak
Normal file
55
editors/kak/a48s.kak
Normal file
@ -0,0 +1,55 @@
|
||||
# ain48 assembly syntax highlighting
|
||||
# put this in your autoload folder in ~/.config/kak/autoload and it should work
|
||||
# note: if you are *creating* an autoload folder in that location,
|
||||
# the *default* autoload scripts in /usr/share/kak/autoload will not trigger,
|
||||
# so it might be a good idea to copy the contents of that directory.
|
||||
|
||||
hook global BufCreate .*\.(a|ain)48(s|asm) %{
|
||||
set-option buffer filetype a48s
|
||||
}
|
||||
|
||||
hook global WinSetOption filetype=a48s %{
|
||||
require-module a48s
|
||||
hook -once -always window WinSetOption filetype=.* %{
|
||||
remove-hooks window a48s-.+
|
||||
}
|
||||
}
|
||||
|
||||
hook -group a48s-highlight global WinSetOption filetype=a48s %{
|
||||
add-highlighter window/a48s ref a48s
|
||||
hook -once -always window WinSetOption filetype=.* %{
|
||||
remove-highlighter window/a48s
|
||||
}
|
||||
}
|
||||
|
||||
provide-module a48s %{
|
||||
|
||||
add-highlighter shared/a48s regions
|
||||
add-highlighter shared/a48s/ region ';' '\n' fill comment
|
||||
add-highlighter shared/a48s/dqstring region '"' '"' group
|
||||
add-highlighter shared/a48s/dqstring/ fill string
|
||||
add-highlighter shared/a48s/dqstring/ \
|
||||
regex (\\[\\abefhnrtv\n])|(\\.) 1:keyword 2:Error
|
||||
add-highlighter shared/a48s/code default-region group
|
||||
|
||||
# immediates
|
||||
add-highlighter shared/a48s/code/ regex \
|
||||
(?i)#-?(s[0-5]+|o[0-7]+|b[01]+|x[0-9]+)\b \
|
||||
0:value
|
||||
|
||||
# registers
|
||||
add-highlighter shared/a48s/code/ regex (?i)%([a-z0-7]+)\b 0:builtin
|
||||
|
||||
# directives
|
||||
add-highlighter shared/a48s/code/ regex \.[a-zA-Z]+ 0:type
|
||||
|
||||
# labels
|
||||
add-highlighter shared/a48s/code/ regex ^\h*[A-Za-z0-9_.-]+: 0:operator
|
||||
|
||||
# instructions
|
||||
add-highlighter shared/a48s/code/ regex \
|
||||
(?i)\b((p?(add|dem|dvd|i[mp]?lg|mpl|rsd|str))|(n?[enpu]?i)|(ir|nc)?rv|(nc)?ivc|aeq|an|aut|cess|cst|dem|dst|et|(p?[sbq])?(lg|sc)|nam|nec|sim|tsc|vel)\b \
|
||||
0:keyword
|
||||
# the regex is painfully long but i can't do anything about that so...
|
||||
|
||||
}
|
||||
6
editors/vim/ftdetect/ain48asm.vim
Normal file
6
editors/vim/ftdetect/ain48asm.vim
Normal file
@ -0,0 +1,6 @@
|
||||
" ftdetect file for AIN-48 assembly
|
||||
|
||||
au BufRead,BufNewFile *.ain48s set filetype=ain48asm
|
||||
au BufRead,BufNewFile *.ain48asm set filetype=ain48asm
|
||||
au BufRead,BufNewFile *.a48s set filetype=ain48asm
|
||||
au BufRead,BufNewFile *.a48asm set filetype=ain48asm
|
||||
39
editors/vim/syntax/ain48asm.vim
Normal file
39
editors/vim/syntax/ain48asm.vim
Normal file
@ -0,0 +1,39 @@
|
||||
" Vim syntax file
|
||||
" Language: AIN-48 Assembly
|
||||
" Maintainer: Annwan
|
||||
" Latest Revision: 31 May 2026
|
||||
|
||||
if exists("b:current_syntax")
|
||||
finish
|
||||
endif
|
||||
|
||||
syn case ignore
|
||||
syn keyword ain48Mnemonic add aeq aut cess cst dem dst dvd ei et i ilg imlg iplg irrv ivc lg mpl nam ncivc ncrv nec nei ni nni npi nui padd pdem pdvd pi pilg pimlg piplg pmpl prsd pstr rsd rv sc sim str tsc ui vel
|
||||
|
||||
" Senary constants
|
||||
syn match ain48Immediate "#[Ss][0-5]\+"
|
||||
syn match ain48Immediate "#-[Ss][0-5]\+"
|
||||
" Octal constants
|
||||
syn match ain48Immediate "#[Oo][0-7]\+"
|
||||
syn match ain48Immediate "#-[Oo][0-7]\+"
|
||||
" Decimal constants
|
||||
syn match ain48Immediate "#[Xx][0-9]\+"
|
||||
syn match ain48Immediate "#-[Xx][0-9]\+"
|
||||
" Binary constants
|
||||
syn match ain48Immediate "#[Bb][01]\+"
|
||||
syn match ain48Immediate "#-[Bb][01]\+"
|
||||
|
||||
syn match ain48Register "%[0-7a-z]\+"
|
||||
syn match ain48Directive "\.[a-z0-9_-]\+"
|
||||
|
||||
syn match ain48Comment ";.*$" contains=ain48Todo
|
||||
syn keyword ain48Todo contained TODO FIXME NOTE
|
||||
|
||||
syn match ain48Label "^[a-zA-Z0-9_-]\+:"
|
||||
|
||||
hi link ain48Mnemonic Statement
|
||||
hi link ain48Comment Comment
|
||||
hi link ain48Immediate Constant
|
||||
hi link ain48Directive PreProc
|
||||
hi link ain48Label Label
|
||||
hi link ain48Register Identifier
|
||||
@ -1,67 +0,0 @@
|
||||
#ifndef AIN48__H
|
||||
#define AIN48__H
|
||||
|
||||
#include <assert.h>
|
||||
#include <common.h>
|
||||
|
||||
enum instruction_format {
|
||||
AMAL,
|
||||
IML,
|
||||
IPL,
|
||||
AMLS,
|
||||
ASSS,
|
||||
ASLI,
|
||||
ASLR,
|
||||
ASRD,
|
||||
};
|
||||
|
||||
enum amal_ac : u8 {
|
||||
ADD = 000,
|
||||
STR = 001,
|
||||
MPL = 002,
|
||||
DVD = 004,
|
||||
RSD = 005,
|
||||
DEM = 006,
|
||||
ET = 010,
|
||||
VEL = 011,
|
||||
AUT = 012,
|
||||
NAM = 014,
|
||||
NEC = 015,
|
||||
};
|
||||
|
||||
enum asss_ac : u8 {
|
||||
RV = 00,
|
||||
IRRV = 04,
|
||||
NCIVC = 03,
|
||||
NCRV = 02,
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
struct instruction {
|
||||
enum instruction_format format;
|
||||
union {
|
||||
struct {
|
||||
bool s, i1, i2; enum amal_ac ac; u4 rf;
|
||||
union {
|
||||
u8 imm; i8 simm;
|
||||
struct {
|
||||
union { u4 r2; u4 imm2; i4 simm2; };
|
||||
union { u4 r1; u4 imm1; u4 simm1; };
|
||||
};
|
||||
} data;
|
||||
} AMAL;
|
||||
struct { u4 r; u48 imm; } IML;
|
||||
struct { bool s; u4 r; union { u12 imm; i12 simm; }; } IPL;
|
||||
struct { bool s; u4 rd; u4 rl; i12 imm; } AMLS;
|
||||
enum asss_ac ASSS_ac;
|
||||
struct { bool I, E, N, U, R; u48 imm; } ASLI;
|
||||
struct { bool I, E, N, U, R; u4 rl; } ASLR;
|
||||
struct { bool I, E, N, U, R; u4 rl; i12 imm; } ASRD;
|
||||
};
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
u12 *ain48_read_instr(u12 *code, struct instruction *i);
|
||||
u12 *ain48_write_instr(u12 *code, struct instruction *i);
|
||||
|
||||
#endif // AIN48__H
|
||||
@ -1,48 +0,0 @@
|
||||
#ifndef __UCSD_COMMON_H__
|
||||
#define __UCSD_COMMON_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// # NUMBER TYPES
|
||||
typedef unsigned _BitInt(4) u4;
|
||||
typedef uint8_t u8;
|
||||
typedef unsigned _BitInt(12) u12;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef unsigned _BitInt(48) u48;
|
||||
typedef uint64_t u64;
|
||||
typedef unsigned __int128 u128;
|
||||
|
||||
typedef size_t usz;
|
||||
typedef uintptr_t uptr;
|
||||
|
||||
typedef _BitInt(4) i4;
|
||||
typedef int8_t i8;
|
||||
typedef _BitInt(12) i12;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef _BitInt(48) i48;
|
||||
typedef int64_t i64;
|
||||
typedef __int128 i128;
|
||||
typedef ssize_t isz;
|
||||
typedef intptr_t iptr;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
// # LOGGING FACILITES
|
||||
|
||||
[[gnu::format(printf, 1, 2)]] void log_debug(char const *format, ...);
|
||||
[[gnu::format(printf, 1, 2)]] void log_warn(char const *format, ...);
|
||||
[[gnu::format(printf, 1, 2)]] void log_err(char const *format, ...);
|
||||
[[gnu::format(printf, 1, 2)]] void log_err_errno(char const *format, ...);
|
||||
void set_log_opts(FILE *f, bool colours);
|
||||
|
||||
extern int foo;
|
||||
|
||||
#endif // ndef __UCSD_COMMON_H__
|
||||
34
programs/ain48.cabal
Normal file
34
programs/ain48.cabal
Normal file
@ -0,0 +1,34 @@
|
||||
cabal-version: 3.0
|
||||
-- The cabal-version field refers to the version of the .cabal specification,
|
||||
-- and can be different from the cabal-install (the tool) version and the
|
||||
-- Cabal (the library) version you are using. As such, the Cabal (the library)
|
||||
-- version used must be equal or greater than the version stated in this field.
|
||||
-- Starting from the specification version 2.2, the cabal-version field must be
|
||||
-- the first thing in the cabal file.
|
||||
|
||||
-- Initial package description 'ain48' generated by
|
||||
name: ain48
|
||||
version: 0.1.0.0
|
||||
homepage: https://git.annwan.me/worldbuilding/ain48
|
||||
license: MIT
|
||||
author: Annwan
|
||||
maintainer: annwan@annwan.me
|
||||
build-type: Simple
|
||||
|
||||
common warnings
|
||||
ghc-options: -Wall
|
||||
library
|
||||
default-language: GHC2024
|
||||
hs-source-dirs: common
|
||||
build-depends: base ^>= 4.21.2.0
|
||||
exposed-modules: Ain48.Types
|
||||
|
||||
executable dump12
|
||||
import: warnings
|
||||
main-is: Main.hs
|
||||
-- other-modules:
|
||||
build-depends: base ^>=4.21.2.0
|
||||
, ain48
|
||||
, optparse-applicative
|
||||
hs-source-dirs: dump12
|
||||
default-language: GHC2024
|
||||
383
programs/common/Ain48/Types.hs
Normal file
383
programs/common/Ain48/Types.hs
Normal file
@ -0,0 +1,383 @@
|
||||
module Ain48.Types
|
||||
( module Data.Word
|
||||
, module Data.Int
|
||||
, Word4(..), Word6(..), Word12(..), Word24(..), Word48(..)
|
||||
, Int4(..), Int6(..), Int12(..), Int24(..), Int48(..),
|
||||
) where
|
||||
|
||||
import Data.Word (Word8, Word16, Word32, Word64)
|
||||
import Data.Int (Int8, Int16, Int32, Int64)
|
||||
import Data.Bits ((.&.))
|
||||
import Data.Bifunctor (bimap)
|
||||
newtype Word4 = Word4 { unWord4 :: Word8 } deriving (Eq)
|
||||
instance Show Word4 where
|
||||
show :: Word4 -> String
|
||||
show = show . unWord4
|
||||
instance Num Word4 where
|
||||
(+) :: Word4 -> Word4 -> Word4
|
||||
(+) a b = Word4 $ unWord4 a + unWord4 b
|
||||
(*) :: Word4 -> Word4 -> Word4
|
||||
(*) a b = Word4 $ unWord4 a * unWord4 b
|
||||
(-) :: Word4 -> Word4 -> Word4
|
||||
(-) a b = Word4 $ unWord4 a - unWord4 b
|
||||
abs :: Word4 -> Word4
|
||||
abs = Word4 . abs . unWord4
|
||||
signum :: Word4 -> Word4
|
||||
signum = Word4 . signum . unWord4
|
||||
fromInteger :: Integer -> Word4
|
||||
fromInteger = Word4 . (.&. 0xF) . fromInteger
|
||||
instance Ord Word4 where
|
||||
compare :: Word4 -> Word4 -> Ordering
|
||||
compare a b = compare (unWord4 a) (unWord4 b)
|
||||
instance Real Word4 where
|
||||
toRational :: Word4 -> Rational
|
||||
toRational = toRational . unWord4
|
||||
instance Bounded Word4 where
|
||||
minBound :: Word4
|
||||
minBound = Word4 0
|
||||
maxBound :: Word4
|
||||
maxBound = Word4 0xF
|
||||
instance Enum Word4 where
|
||||
fromEnum :: Word4 -> Int
|
||||
fromEnum = fromEnum . unWord4
|
||||
toEnum :: Int -> Word4
|
||||
toEnum = Word4 . (.&. 0xF) . toEnum
|
||||
instance Integral Word4 where
|
||||
quotRem :: Word4 -> Word4 -> (Word4, Word4)
|
||||
quotRem a b = bimap Word4 Word4 $ quotRem (unWord4 a) (unWord4 b)
|
||||
toInteger :: Word4 -> Integer
|
||||
toInteger = toInteger . unWord4
|
||||
newtype Word6 = Word6 { unWord6 :: Word8 } deriving (Eq)
|
||||
instance Show Word6 where
|
||||
show :: Word6 -> String
|
||||
show = show . unWord6
|
||||
instance Num Word6 where
|
||||
(+) :: Word6 -> Word6 -> Word6
|
||||
(+) a b = Word6 $ unWord6 a + unWord6 b
|
||||
(*) :: Word6 -> Word6 -> Word6
|
||||
(*) a b = Word6 $ unWord6 a * unWord6 b
|
||||
(-) :: Word6 -> Word6 -> Word6
|
||||
(-) a b = Word6 $ unWord6 a - unWord6 b
|
||||
abs :: Word6 -> Word6
|
||||
abs = Word6 . abs . unWord6
|
||||
signum :: Word6 -> Word6
|
||||
signum = Word6 . signum . unWord6
|
||||
fromInteger :: Integer -> Word6
|
||||
fromInteger = Word6 . (.&. 0x3F) . fromInteger
|
||||
instance Ord Word6 where
|
||||
compare :: Word6 -> Word6 -> Ordering
|
||||
compare a b = compare (unWord6 a) (unWord6 b)
|
||||
instance Real Word6 where
|
||||
toRational :: Word6 -> Rational
|
||||
toRational = toRational . unWord6
|
||||
instance Bounded Word6 where
|
||||
minBound :: Word6
|
||||
minBound = Word6 0
|
||||
maxBound :: Word6
|
||||
maxBound = Word6 0x3F
|
||||
instance Enum Word6 where
|
||||
fromEnum :: Word6 -> Int
|
||||
fromEnum = fromEnum . unWord6
|
||||
toEnum :: Int -> Word6
|
||||
toEnum = Word6 . (.&. 0x3F) . toEnum
|
||||
instance Integral Word6 where
|
||||
quotRem :: Word6 -> Word6 -> (Word6, Word6)
|
||||
quotRem a b = bimap Word6 Word6 $ quotRem (unWord6 a) (unWord6 b)
|
||||
toInteger :: Word6 -> Integer
|
||||
toInteger = toInteger . unWord6
|
||||
newtype Word12 = Word12 { unWord12 :: Word16 } deriving (Eq)
|
||||
instance Show Word12 where
|
||||
show :: Word12 -> String
|
||||
show = show . unWord12
|
||||
instance Num Word12 where
|
||||
(+) :: Word12 -> Word12 -> Word12
|
||||
(+) a b = Word12 $ unWord12 a + unWord12 b
|
||||
(*) :: Word12 -> Word12 -> Word12
|
||||
(*) a b = Word12 $ unWord12 a * unWord12 b
|
||||
(-) :: Word12 -> Word12 -> Word12
|
||||
(-) a b = Word12 $ unWord12 a - unWord12 b
|
||||
abs :: Word12 -> Word12
|
||||
abs = Word12 . abs . unWord12
|
||||
signum :: Word12 -> Word12
|
||||
signum = Word12 . signum . unWord12
|
||||
fromInteger :: Integer -> Word12
|
||||
fromInteger = Word12 . (.&. 0xFFF) . fromInteger
|
||||
instance Ord Word12 where
|
||||
compare :: Word12 -> Word12 -> Ordering
|
||||
compare a b = compare (unWord12 a) (unWord12 b)
|
||||
instance Real Word12 where
|
||||
toRational :: Word12 -> Rational
|
||||
toRational = toRational . unWord12
|
||||
instance Bounded Word12 where
|
||||
minBound :: Word12
|
||||
minBound = Word12 0
|
||||
maxBound :: Word12
|
||||
maxBound = Word12 0xFFF
|
||||
instance Enum Word12 where
|
||||
fromEnum :: Word12 -> Int
|
||||
fromEnum = fromEnum . unWord12
|
||||
toEnum :: Int -> Word12
|
||||
toEnum = Word12 . (.&. 0xFFF) . toEnum
|
||||
instance Integral Word12 where
|
||||
quotRem :: Word12 -> Word12 -> (Word12, Word12)
|
||||
quotRem a b = bimap Word12 Word12 $ quotRem (unWord12 a) (unWord12 b)
|
||||
toInteger :: Word12 -> Integer
|
||||
toInteger = toInteger . unWord12
|
||||
newtype Word24 = Word24 { unWord24 :: Word32 } deriving (Eq)
|
||||
instance Show Word24 where
|
||||
show :: Word24 -> String
|
||||
show = show . unWord24
|
||||
instance Num Word24 where
|
||||
(+) :: Word24 -> Word24 -> Word24
|
||||
(+) a b = Word24 $ unWord24 a + unWord24 b
|
||||
(*) :: Word24 -> Word24 -> Word24
|
||||
(*) a b = Word24 $ unWord24 a * unWord24 b
|
||||
(-) :: Word24 -> Word24 -> Word24
|
||||
(-) a b = Word24 $ unWord24 a - unWord24 b
|
||||
abs :: Word24 -> Word24
|
||||
abs = Word24 . abs . unWord24
|
||||
signum :: Word24 -> Word24
|
||||
signum = Word24 . signum . unWord24
|
||||
fromInteger :: Integer -> Word24
|
||||
fromInteger = Word24 . (.&. 0xFFFFFF) . fromInteger
|
||||
instance Ord Word24 where
|
||||
compare :: Word24 -> Word24 -> Ordering
|
||||
compare a b = compare (unWord24 a) (unWord24 b)
|
||||
instance Real Word24 where
|
||||
toRational :: Word24 -> Rational
|
||||
toRational = toRational . unWord24
|
||||
instance Bounded Word24 where
|
||||
minBound :: Word24
|
||||
minBound = Word24 0
|
||||
maxBound :: Word24
|
||||
maxBound = Word24 0xFFFFFF
|
||||
instance Enum Word24 where
|
||||
fromEnum :: Word24 -> Int
|
||||
fromEnum = fromEnum . unWord24
|
||||
toEnum :: Int -> Word24
|
||||
toEnum = Word24 . (.&. 0xFFFFFF) . toEnum
|
||||
instance Integral Word24 where
|
||||
quotRem :: Word24 -> Word24 -> (Word24, Word24)
|
||||
quotRem a b = bimap Word24 Word24 $ quotRem (unWord24 a) (unWord24 b)
|
||||
toInteger :: Word24 -> Integer
|
||||
toInteger = toInteger . unWord24
|
||||
newtype Word48 = Word48 { unWord48 :: Word64 } deriving (Eq)
|
||||
instance Show Word48 where
|
||||
show :: Word48 -> String
|
||||
show = show . unWord48
|
||||
instance Num Word48 where
|
||||
(+) :: Word48 -> Word48 -> Word48
|
||||
(+) a b = Word48 $ unWord48 a + unWord48 b
|
||||
(*) :: Word48 -> Word48 -> Word48
|
||||
(*) a b = Word48 $ unWord48 a * unWord48 b
|
||||
(-) :: Word48 -> Word48 -> Word48
|
||||
(-) a b = Word48 $ unWord48 a - unWord48 b
|
||||
abs :: Word48 -> Word48
|
||||
abs = Word48 . abs . unWord48
|
||||
signum :: Word48 -> Word48
|
||||
signum = Word48 . signum . unWord48
|
||||
fromInteger :: Integer -> Word48
|
||||
fromInteger = Word48 . (.&. 0xFFFFFFFFFFFF) . fromInteger
|
||||
instance Ord Word48 where
|
||||
compare :: Word48 -> Word48 -> Ordering
|
||||
compare a b = compare (unWord48 a) (unWord48 b)
|
||||
instance Real Word48 where
|
||||
toRational :: Word48 -> Rational
|
||||
toRational = toRational . unWord48
|
||||
instance Bounded Word48 where
|
||||
minBound :: Word48
|
||||
minBound = Word48 0
|
||||
maxBound :: Word48
|
||||
maxBound = Word48 0xFFFFFFFFFFFF
|
||||
instance Enum Word48 where
|
||||
fromEnum :: Word48 -> Int
|
||||
fromEnum = fromEnum . unWord48
|
||||
toEnum :: Int -> Word48
|
||||
toEnum = Word48 . (.&. 0xFFFFFFFFFFFF) . toEnum
|
||||
instance Integral Word48 where
|
||||
quotRem :: Word48 -> Word48 -> (Word48, Word48)
|
||||
quotRem a b = bimap Word48 Word48 $ quotRem (unWord48 a) (unWord48 b)
|
||||
toInteger :: Word48 -> Integer
|
||||
toInteger = toInteger . unWord48
|
||||
newtype Int4 = Int4 { unInt4 :: Int8 } deriving (Eq)
|
||||
instance Show Int4 where
|
||||
show :: Int4 -> String
|
||||
show = show . unInt4
|
||||
instance Num Int4 where
|
||||
(+) :: Int4 -> Int4 -> Int4
|
||||
(+) a b = Int4 $ unInt4 a + unInt4 b
|
||||
(*) :: Int4 -> Int4 -> Int4
|
||||
(*) a b = Int4 $ unInt4 a * unInt4 b
|
||||
(-) :: Int4 -> Int4 -> Int4
|
||||
(-) a b = Int4 $ unInt4 a - unInt4 b
|
||||
abs :: Int4 -> Int4
|
||||
abs = Int4 . abs . unInt4
|
||||
signum :: Int4 -> Int4
|
||||
signum = Int4 . signum . unInt4
|
||||
fromInteger :: Integer -> Int4
|
||||
fromInteger = Int4 . (.&. 0xF) . fromInteger
|
||||
instance Ord Int4 where
|
||||
compare :: Int4 -> Int4 -> Ordering
|
||||
compare a b = compare (unInt4 a) (unInt4 b)
|
||||
instance Real Int4 where
|
||||
toRational :: Int4 -> Rational
|
||||
toRational = toRational . unInt4
|
||||
instance Bounded Int4 where
|
||||
minBound :: Int4
|
||||
minBound = Int4 (-8)
|
||||
maxBound :: Int4
|
||||
maxBound = Int4 7
|
||||
instance Enum Int4 where
|
||||
fromEnum :: Int4 -> Int
|
||||
fromEnum = fromEnum . unInt4
|
||||
toEnum :: Int -> Int4
|
||||
toEnum = Int4 . (.&. 0xF) . toEnum
|
||||
instance Integral Int4 where
|
||||
quotRem :: Int4 -> Int4 -> (Int4, Int4)
|
||||
quotRem a b = bimap Int4 Int4 $ quotRem (unInt4 a) (unInt4 b)
|
||||
toInteger :: Int4 -> Integer
|
||||
toInteger = toInteger . unInt4
|
||||
newtype Int6 = Int6 { unInt6 :: Int8 } deriving (Eq)
|
||||
instance Show Int6 where
|
||||
show :: Int6 -> String
|
||||
show = show . unInt6
|
||||
instance Num Int6 where
|
||||
(+) :: Int6 -> Int6 -> Int6
|
||||
(+) a b = Int6 $ unInt6 a + unInt6 b
|
||||
(*) :: Int6 -> Int6 -> Int6
|
||||
(*) a b = Int6 $ unInt6 a * unInt6 b
|
||||
(-) :: Int6 -> Int6 -> Int6
|
||||
(-) a b = Int6 $ unInt6 a - unInt6 b
|
||||
abs :: Int6 -> Int6
|
||||
abs = Int6 . abs . unInt6
|
||||
signum :: Int6 -> Int6
|
||||
signum = Int6 . signum . unInt6
|
||||
fromInteger :: Integer -> Int6
|
||||
fromInteger = Int6 . (.&. 0x3F) . fromInteger
|
||||
instance Ord Int6 where
|
||||
compare :: Int6 -> Int6 -> Ordering
|
||||
compare a b = compare (unInt6 a) (unInt6 b)
|
||||
instance Real Int6 where
|
||||
toRational :: Int6 -> Rational
|
||||
toRational = toRational . unInt6
|
||||
instance Bounded Int6 where
|
||||
minBound :: Int6
|
||||
minBound = Int6 (-32)
|
||||
maxBound :: Int6
|
||||
maxBound = Int6 31
|
||||
instance Enum Int6 where
|
||||
fromEnum :: Int6 -> Int
|
||||
fromEnum = fromEnum . unInt6
|
||||
toEnum :: Int -> Int6
|
||||
toEnum = Int6 . (.&. 0x3F) . toEnum
|
||||
instance Integral Int6 where
|
||||
quotRem :: Int6 -> Int6 -> (Int6, Int6)
|
||||
quotRem a b = (bimap Int6 Int6) $ quotRem (unInt6 a) (unInt6 b)
|
||||
toInteger :: Int6 -> Integer
|
||||
toInteger = toInteger . unInt6
|
||||
newtype Int12 = Int12 { unInt12 :: Int16 } deriving (Eq)
|
||||
instance Show Int12 where
|
||||
show :: Int12 -> String
|
||||
show = show . unInt12
|
||||
instance Num Int12 where
|
||||
(+) :: Int12 -> Int12 -> Int12
|
||||
(+) a b = Int12 $ unInt12 a + unInt12 b
|
||||
(*) :: Int12 -> Int12 -> Int12
|
||||
(*) a b = Int12 $ unInt12 a * unInt12 b
|
||||
(-) :: Int12 -> Int12 -> Int12
|
||||
(-) a b = Int12 $ unInt12 a - unInt12 b
|
||||
abs :: Int12 -> Int12
|
||||
abs = Int12 . abs . unInt12
|
||||
signum :: Int12 -> Int12
|
||||
signum = Int12 . signum . unInt12
|
||||
fromInteger :: Integer -> Int12
|
||||
fromInteger = Int12 . (.&. 0xFFF) . fromInteger
|
||||
instance Ord Int12 where
|
||||
compare :: Int12 -> Int12 -> Ordering
|
||||
compare a b = compare (unInt12 a) (unInt12 b)
|
||||
instance Real Int12 where
|
||||
toRational :: Int12 -> Rational
|
||||
toRational = toRational . unInt12
|
||||
instance Bounded Int12 where
|
||||
minBound :: Int12
|
||||
minBound = Int12 (-2048)
|
||||
maxBound :: Int12
|
||||
maxBound = Int12 2047
|
||||
instance Enum Int12 where
|
||||
fromEnum :: Int12 -> Int
|
||||
fromEnum = fromEnum . unInt12
|
||||
toEnum :: Int -> Int12
|
||||
toEnum = Int12 . (.&. 0xFFF) . toEnum
|
||||
instance Integral Int12 where
|
||||
quotRem :: Int12 -> Int12 -> (Int12, Int12)
|
||||
quotRem a b = bimap Int12 Int12 $ quotRem (unInt12 a) (unInt12 b)
|
||||
toInteger :: Int12 -> Integer
|
||||
toInteger = toInteger . unInt12
|
||||
newtype Int24 = Int24 { unInt24 :: Int32 } deriving (Eq)
|
||||
instance Show Int24 where
|
||||
show :: Int24 -> String
|
||||
show = show . unInt24
|
||||
instance Num Int24 where
|
||||
(+) :: Int24 -> Int24 -> Int24
|
||||
(+) a b = Int24 $ unInt24 a + unInt24 b
|
||||
(*) :: Int24 -> Int24 -> Int24
|
||||
(*) a b = Int24 $ unInt24 a * unInt24 b
|
||||
(-) :: Int24 -> Int24 -> Int24
|
||||
(-) a b = Int24 $ unInt24 a - unInt24 b
|
||||
abs :: Int24 -> Int24
|
||||
abs = Int24 . abs . unInt24
|
||||
signum :: Int24 -> Int24
|
||||
signum = Int24 . signum . unInt24
|
||||
fromInteger :: Integer -> Int24
|
||||
fromInteger = Int24 . (.&. 0xFFFFFF) . fromInteger
|
||||
instance Ord Int24 where
|
||||
compare :: Int24 -> Int24 -> Ordering
|
||||
compare a b = compare (unInt24 a) (unInt24 b)
|
||||
instance Real Int24 where
|
||||
toRational :: Int24 -> Rational
|
||||
toRational = toRational . unInt24
|
||||
instance Bounded Int24 where
|
||||
minBound :: Int24
|
||||
minBound = Int24 (-8388608)
|
||||
maxBound :: Int24
|
||||
maxBound = Int24 8388607
|
||||
instance Enum Int24 where
|
||||
fromEnum :: Int24 -> Int
|
||||
fromEnum = fromEnum . unInt24
|
||||
toEnum :: Int -> Int24
|
||||
toEnum = Int24 . (.&. 0xFFFFFF) . toEnum
|
||||
instance Integral Int24 where
|
||||
quotRem :: Int24 -> Int24 -> (Int24, Int24)
|
||||
quotRem a b = bimap Int24 Int24 $ quotRem (unInt24 a) (unInt24 b)
|
||||
toInteger :: Int24 -> Integer
|
||||
toInteger = toInteger . unInt24
|
||||
newtype Int48 = Int48 { unInt48 :: Int64 } deriving (Eq)
|
||||
instance Show Int48 where
|
||||
show :: Int48 -> String
|
||||
show = show . unInt48
|
||||
instance Num Int48 where
|
||||
(+) :: Int48 -> Int48 -> Int48
|
||||
(+) a b = Int48 $ unInt48 a + unInt48 b
|
||||
(*) :: Int48 -> Int48 -> Int48
|
||||
(*) a b = Int48 $ unInt48 a * unInt48 b
|
||||
(-) :: Int48 -> Int48 -> Int48
|
||||
(-) a b = Int48 $ unInt48 a - unInt48 b
|
||||
abs :: Int48 -> Int48
|
||||
abs = Int48 . abs . unInt48
|
||||
signum :: Int48 -> Int48
|
||||
signum = Int48 . signum . unInt48
|
||||
fromInteger = Int48 . (.&. 0xFFFFFFFFFFFF) . fromInteger
|
||||
instance Ord Int48 where
|
||||
compare a b = compare (unInt48 a) (unInt48 b)
|
||||
instance Real Int48 where
|
||||
toRational = toRational . unInt48
|
||||
instance Bounded Int48 where
|
||||
minBound = Int48 (-140737488355328)
|
||||
maxBound = Int48 140737488355327
|
||||
instance Enum Int48 where
|
||||
fromEnum = fromEnum . unInt48
|
||||
toEnum = Int48 . (.&. 0xFFFFFFFFFFFF) . toEnum
|
||||
instance Integral Int48 where
|
||||
quotRem a b = (\(a, b) -> (Int48 a, Int48 b)) $ quotRem (unInt48 a) (unInt48 b)
|
||||
toInteger = toInteger . unInt48
|
||||
|
||||
16
programs/dump12/Main.hs
Normal file
16
programs/dump12/Main.hs
Normal file
@ -0,0 +1,16 @@
|
||||
module Main (main) where
|
||||
|
||||
import Ain48.Types
|
||||
import Options.Applicative
|
||||
|
||||
parser_opts :: Parser Bool
|
||||
parser_opts = switch ( long "decode"
|
||||
<> short 'd'
|
||||
<> help "Decode a binary file instead of encoding a dump file")
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
opts <- execParser $ info (parser_opts <**> helper)
|
||||
( fullDesc <> progDesc "Convert to and from 12 bit byte binaries"
|
||||
<> header "dump12 --- conversion utility" )
|
||||
print opts
|
||||
191
src/ain48.c
191
src/ain48.c
@ -1,191 +0,0 @@
|
||||
#include <ain48.h>
|
||||
#include <string.h>
|
||||
|
||||
u12 *ain48_write_instruction(u12 *code, struct instruction *i) {
|
||||
u4 u4tmp;
|
||||
u8 u8tmp;
|
||||
switch (i->format) {
|
||||
case AMAL:
|
||||
*code++ = i->AMAL.ac | (i->AMAL.s ? 1 << 4 : 0) |
|
||||
(i->AMAL.i1 ? 1 << 5 : 0) | (i->AMAL.i2 ? 1 << 6 : 0);
|
||||
*code = ((u12)i->AMAL.rf) << 8;
|
||||
if (!i->AMAL.i1)
|
||||
*code |= ((u12)i->AMAL.data.r1) << 4;
|
||||
if (!i->AMAL.i2)
|
||||
*code |= ((u12)i->AMAL.data.r2);
|
||||
if (i->AMAL.i1 && i->AMAL.i2) {
|
||||
if (i->AMAL.s)
|
||||
memcpy(&u8tmp, &i->AMAL.data.simm, sizeof(u8));
|
||||
else
|
||||
u8tmp = i->AMAL.data.imm;
|
||||
*code |= u8tmp;
|
||||
} else if (i->AMAL.i1) {
|
||||
if (i->AMAL.s)
|
||||
memcpy(&u4tmp, &i->AMAL.data.simm1, sizeof(u4));
|
||||
else
|
||||
u4tmp = i->AMAL.data.imm1;
|
||||
*code |= u4tmp;
|
||||
} else if (i->AMAL.i2) {
|
||||
if (i->AMAL.s)
|
||||
memcpy(&u4tmp, &i->AMAL.data.simm2, sizeof(u4));
|
||||
else
|
||||
u4tmp = i->AMAL.data.imm2;
|
||||
*code |= ((u12)u4tmp) << 4;
|
||||
}
|
||||
return ++code;
|
||||
case IML:
|
||||
*code++ = 00400 | i->IML.r;
|
||||
*code++ = i->IML.imm & 07777;
|
||||
*code++ = (i->IML.imm >> 12) & 07777;
|
||||
*code++ = (i->IML.imm >> 24) & 07777;
|
||||
*code++ = (i->IML.imm >> 36) & 07777;
|
||||
return code;
|
||||
case IPL:
|
||||
*code++ = 00500 | (i->IPL.s ? (1 << 4) : 0) | i->IPL.r;
|
||||
if (i->IPL.s) {
|
||||
memcpy(code++, &i->IPL.simm, sizeof(u12));
|
||||
} else {
|
||||
*code++ = i->IPL.imm;
|
||||
}
|
||||
return code;
|
||||
case AMLS:
|
||||
*code++ = 01000 | (i->AMLS.s ? 1 << 8 : 0) | (((u12)i->AMLS.rd) << 4) |
|
||||
i->AMLS.rl;
|
||||
memcpy(code++, &i->AMLS.imm, sizeof(u12));
|
||||
return code;
|
||||
case ASSS:
|
||||
*code++ = 07770 | i->ASSS_ac;
|
||||
return code;
|
||||
case ASLI:
|
||||
*code++ = 04000 | (i->ASLI.R ? 1 << 0 : 0) | (i->ASLI.U ? 1 << 1 : 0) |
|
||||
(i->ASLI.N ? 1 << 2 : 0) | (i->ASLI.E ? 1 << 3 : 0) |
|
||||
(i->ASLI.I ? 1 << 4 : 0);
|
||||
*code++ = i->ASLI.imm & 07777;
|
||||
*code++ = (i->ASLI.imm >> 12) & 07777;
|
||||
*code++ = (i->ASLI.imm >> 24) & 07777;
|
||||
*code++ = (i->ASLI.imm >> 36) & 07777;
|
||||
return code;
|
||||
case ASLR:
|
||||
*code++ = 05000 | (i->ASLR.R ? 1 << 0 : 0) | (i->ASLR.U ? 1 << 1 : 0) |
|
||||
(i->ASLR.N ? 1 << 2 : 0) | (i->ASLR.E ? 1 << 3 : 0) |
|
||||
(i->ASLR.I ? 1 << 4 : 0) | (((u12)i->ASLR.rl) << 5);
|
||||
return code;
|
||||
case ASRD:
|
||||
*code++ = 05000 | (i->ASRD.R ? 1 << 0 : 0) | (i->ASRD.U ? 1 << 1 : 0) |
|
||||
(i->ASRD.N ? 1 << 2 : 0) | (i->ASRD.E ? 1 << 3 : 0) |
|
||||
(i->ASLR.I ? 1 << 4 : 0) | (((u12)i->ASRD.rl) << 5);
|
||||
memcpy(code++, &i->ASRD.imm, sizeof(u12));
|
||||
return code;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
u12 *ain48_read_instr(u12 *code, struct instruction *i) {
|
||||
u12 byte = *code++;
|
||||
if ((byte & 07600) == 0) { // AMAL
|
||||
i->format = AMAL;
|
||||
i->AMAL.i1 = (byte & 00040) > 0;
|
||||
i->AMAL.i2 = (byte & 00100) > 0;
|
||||
i->AMAL.s = (byte & 00020) > 0;
|
||||
i->AMAL.ac = (enum amal_ac) (byte & 00017);
|
||||
byte = *code++;
|
||||
i->AMAL.rf = (byte >> 8) & 017;
|
||||
if (!i->AMAL.i1)
|
||||
i->AMAL.data.r1 = (byte >> 4) & 017;
|
||||
if (!i->AMAL.i2)
|
||||
i->AMAL.data.r2 = byte & 017;
|
||||
if (i->AMAL.i1 && i->AMAL.i2) {
|
||||
if (i->AMAL.s) {
|
||||
u8 tmp = byte & 0377;
|
||||
memcpy(&i->AMAL.data.simm, &tmp, sizeof(i8));
|
||||
} else
|
||||
i->AMAL.data.imm = byte & 0337;
|
||||
} else if (i->AMAL.i1) {
|
||||
if (i->AMAL.s) {
|
||||
u4 tmp = byte & 017;
|
||||
memcpy(&i->AMAL.data.simm1, &tmp, sizeof(i4));
|
||||
}
|
||||
else
|
||||
i->AMAL.data.imm1 = byte & 017;
|
||||
} else if (i->AMAL.i2) {
|
||||
if (i->AMAL.s) {
|
||||
u4 tmp = (byte >> 4) & 017;
|
||||
memcpy(&i->AMAL.data.simm2, &tmp, sizeof(i4));
|
||||
}
|
||||
else
|
||||
i->AMAL.data.imm2 = (byte >> 4) & 017;
|
||||
}
|
||||
return code;
|
||||
} else if ((byte & 07600) == 00400) { // IML
|
||||
i->format = IML;
|
||||
i->IML.r = byte & 017;
|
||||
byte = *code++;
|
||||
i->IML.imm = (u48)byte;
|
||||
byte = *code++;
|
||||
i->IML.imm |= ((u48)byte << 12);
|
||||
byte = *code++;
|
||||
i->IML.imm |= ((u48)byte << 24);
|
||||
byte = *code++;
|
||||
i->IML.imm |= ((u48)byte << 36);
|
||||
return code;
|
||||
} else if ((byte & 07600) == 00600) { // IPL
|
||||
i->format = IPL;
|
||||
i->IPL.r = byte & 017;
|
||||
i->IPL.s = (byte & 00020) > 0;
|
||||
byte = *code++;
|
||||
if (i->IPL.s) {
|
||||
memcpy(&i->IPL.simm, &byte, sizeof(i12));
|
||||
} else {
|
||||
i->IPL.imm = byte;
|
||||
}
|
||||
return code;
|
||||
} else if ((byte & 07000) == 01000) { // AMLS
|
||||
i->format = AMLS;
|
||||
i->AMLS.s = (byte & 00400) > 0;
|
||||
i->AMLS.rd = (byte >> 4) & 017;
|
||||
i->AMLS.rl = byte & 017;
|
||||
memcpy(&i->AMLS.imm, code++, sizeof(i12));
|
||||
return code;
|
||||
} else if ((byte & 07770) == 07770) { // ASSS
|
||||
i->format = ASSS;
|
||||
i->ASSS_ac = byte & 00007;
|
||||
return code;
|
||||
} else if ((byte & 07000) == 04000) { // ASLI
|
||||
i->format = ASLI;
|
||||
i->ASLI.R = (byte & 0b1) > 0;
|
||||
i->ASLI.U = (byte & 0b10) > 0;
|
||||
i->ASLI.N = (byte & 0b100) > 0;
|
||||
i->ASLI.E = (byte & 0b1000) > 0;
|
||||
i->ASLI.I = (byte & 0b10000) > 0;
|
||||
byte = *code++;
|
||||
i->ASLI.imm = (u48)byte;
|
||||
byte = *code++;
|
||||
i->ASLI.imm |= ((u48)byte << 12);
|
||||
byte = *code++;
|
||||
i->ASLI.imm |= ((u48)byte << 24);
|
||||
byte = *code++;
|
||||
i->ASLI.imm |= ((u48)byte << 36);
|
||||
return code;
|
||||
} else if ((byte & 07000) == 05000) { // ASLR
|
||||
i->format = ASLR;
|
||||
i->ASLR.R = (byte & 0b1) > 0;
|
||||
i->ASLR.U = (byte & 0b10) > 0;
|
||||
i->ASLR.N = (byte & 0b100) > 0;
|
||||
i->ASLR.E = (byte & 0b1000) > 0;
|
||||
i->ASLR.I = (byte & 0b10000) > 0;
|
||||
i->ASLR.rl = (byte >> 5) & 017;
|
||||
return code;
|
||||
} else if ((byte & 07000) == 06000) { // ASRD
|
||||
i->format = ASRD;
|
||||
i->ASRD.R = (byte & 0b1) > 0;
|
||||
i->ASRD.U = (byte & 0b10) > 0;
|
||||
i->ASRD.N = (byte & 0b100) > 0;
|
||||
i->ASRD.E = (byte & 0b1000) > 0;
|
||||
i->ASRD.I = (byte & 0b10000) > 0;
|
||||
i->ASRD.rl = (byte >> 5) & 017;
|
||||
memcpy(&i->ASRD.imm, code++, sizeof(i12));
|
||||
return code;
|
||||
} else return nullptr; // ILLEGAL INSTRUCTION
|
||||
|
||||
}
|
||||
29
src/asm.c
29
src/asm.c
@ -1,29 +0,0 @@
|
||||
#include <common.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <ain48.h>
|
||||
|
||||
i32 asm_main(i32 argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
log_err("Usage: asm source.a48s dest.bin");
|
||||
return 1;
|
||||
}
|
||||
int soruce_file = open(argv[1], O_RDONLY);
|
||||
if (soruce_file < 0) {
|
||||
log_err_errno("Failed to open file `%s`", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
struct stat statres;
|
||||
if (fstat(soruce_file, &statres) < 0) {
|
||||
log_err_errno("Failed to stat file `%s`", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
if (statres.st_size == 0) {
|
||||
log_err("Cannot assemble an empty file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
#include <common.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
FILE *logfile;
|
||||
bool logcolours = true;
|
||||
[[gnu::constructor(101)]] void init_logging() {
|
||||
logfile = stderr;
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
void log_debug([[maybe_unused]] const char* format, ...) {}
|
||||
#else
|
||||
void log_debug(const char* format, ...) {
|
||||
fprintf(logfile, "%s[DEBUG]%s ", logcolours ? "\033[1;44;97m" : "", logcolours ? "\033[0" : "");
|
||||
va_list va;
|
||||
va_start(va);
|
||||
vfprintf(logfile, format, va);
|
||||
va_end(va);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
#endif
|
||||
void log_warn(const char* format, ...) {
|
||||
fprintf(logfile, "%s[WARN]%s ", logcolours ? "\033[1;43;97m": "", logcolours ? "\033[0m" : "");
|
||||
va_list va;
|
||||
va_start(va);
|
||||
vfprintf(logfile, format, va);
|
||||
va_end(va);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
void log_err(const char* format, ...) {
|
||||
fprintf(logfile, "%s[ERROR]%s ", logcolours ? "\033[1;41;97m": "", logcolours ? "\033[0m" : "");
|
||||
va_list va;
|
||||
va_start(va);
|
||||
vfprintf(logfile, format, va);
|
||||
va_end(va);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
void log_err_errno(const char* format, ...) {
|
||||
fprintf(logfile, "%s[ERROR]%s ", logcolours ? "\033[1;41;97m": "", logcolours ? "\033[0m" : "");
|
||||
va_list va;
|
||||
va_start(va);
|
||||
vfprintf(logfile, format, va);
|
||||
va_end(va);
|
||||
fprintf(logfile, ": %s\n", strerror(errno));
|
||||
}
|
||||
void set_log_opts(FILE *f, bool colours) {
|
||||
logfile = f;
|
||||
logcolours = colours;
|
||||
}
|
||||
26
src/main.c
26
src/main.c
@ -1,26 +0,0 @@
|
||||
#include <common.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
enum subprorgram {
|
||||
ASM,
|
||||
SIM,
|
||||
};
|
||||
|
||||
|
||||
const char *available = (R"m(
|
||||
asm)m");
|
||||
|
||||
i32 asm_main(i32 argc, char *argv[]);
|
||||
i32 main(i32 argc, char *argv[]) {
|
||||
if (argc < 2) {
|
||||
log_err("No subprogram called\nAvalible subprograms:%s", available);
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(argv[1], "asm")) {
|
||||
return asm_main(argc - 1, argv + 1);
|
||||
} else {
|
||||
log_err("Unknown subprogram `%s`\nAvailable subpograms:%s", argv[1], available);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user