1
0

Compare commits

...

6 Commits

Author SHA1 Message Date
2317f1e2b7 programs: start rewrite to haskell 2026-06-08 14:03:05 +02:00
30ff19d7ff docs: isa: add sized instructions 2026-06-08 13:59:47 +02:00
cinthyr
52b743de9a tooling: add syntax highlighting for Kakoune
Signed-off-by: Annwan <annwan@annwan.me>
2026-06-05 15:34:49 +02:00
cinthyr
f1ef3d99f1 typo: [0-5]+ > s[0-5]+
Signed-off-by: Annwan <annwan@annwan.me>
2026-06-03 11:25:38 +02:00
3515dee802 typo: asm_main soruce_file > source_file 2026-06-03 00:32:09 +02:00
91a8633243 new: add dump12 utility 2026-06-03 00:31:32 +02:00
15 changed files with 553 additions and 559 deletions

2
.gitignore vendored
View File

@ -4,4 +4,6 @@
/docs/*.pdf
/ain48
/scratch
/programs/dist-newstyle/

View File

@ -1,67 +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 setup
all: setup build docs
setup: compile_flags.txt
build: $(PROGRAM)
docs: $(DOCS)
docs/%.pdf: docs/%.typ
$(TYPST) c $< $@
clean:
$(RM) $(OBJS)
$(RM) $(DEPS)
$(RM) compile_flags.txt
deepclean: clean
$(RM) $(PROGRAM)
$(RM) $(DOCS)
compile_flags.txt: Makefile
printf "%s\n" $(CFLAGS) > $@
$(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)

17
docs/Makefile Normal file
View 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)

View File

@ -6,11 +6,11 @@ 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

View File

@ -27,6 +27,9 @@
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.
@ -79,9 +82,8 @@ memory address.
(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, [ac]),
), ((4, [r#sub[f]]), (4, [r#sub[2]]), (4, [r#sub[1]])))
@ -91,33 +93,8 @@ memory address.
(1, [0]),
(1, [0]),
(1, [0]),
(1, [0]),
(1, [i#sub[2]\ 0]),
(1, [i#sub[1]\ 1]),
(1, [s]),
(4, [ac]),
), ((4, [r#sub[f]]), (4, [r#sub[2]]), (4, text(size: .9em)[imm[0:3]])))
content((12.25, -6))[or]
byte_diag(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[f]]), (4, text(size: .9em)[imm[0:3]]), (4, [r#sub[1]])))
content((12.25, -11))[or]
byte_diag(voff: -15, (
(1, [0]),
(1, [0]),
(1, [0]),
(1, [0]),
(1, [0]),
(1, [i#sub[2]\ 1]),
(1, [i#sub[1]\ 1]),
(2, [m]),
(1, [i\ 1]),
(1, [s]),
(4, [ac]),
), ((4, [r#sub[f]]), (8, [imm[0:7]])))
@ -135,13 +112,13 @@ memory address.
import cetz.draw: *
scale(.65)
byte_diag((
(1, [0]),
(1, [0]),
(1, [0]),
(1, [1]),
(1, [0]),
(1, [0]),
(1, [0]),
(1, [0]),
(1, [s]),
(4, [r]),
), ((12, [imm[0:11]]),))
@ -160,9 +137,9 @@ memory address.
byte_diag((
(1, [0]),
(1, [0]),
(1, [1]),
(1, [1]),
(1, [0]),
(1, [1]),
(1, [1]),
(1, [0]),
(1, [0]),
(1, [s]),
@ -176,9 +153,9 @@ memory address.
import cetz.draw: *
scale(.65)
byte_diag((
(1, [0]),
(1, [0]),
(1, [1]),
(1, [0]),
(1, [s]),
(4, [r#sub[d]]),
(4, [r#sub[l]]),
@ -291,79 +268,65 @@ 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[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[f]][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[f]][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[f]][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)
#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)
#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", "×", true, 1)
#aludoc("MPL", "02", "×", 1)
/ Instruction format: #amal
]),
], ..sized_also("MPL", "Multiplicáre")),
(mnem: "RSD", name: "Residérí", sign: true, description: [
Remainder of the Euclidean division of two signed integers.
Will raise an arithmetic exception if the right operand is zero.
#aludoc("RSD", "05", "mod", false, 1)
#aludoc("RSD", "05", "mod", 1)
/ Instruction format: #amal
]),
], ..sized_also("RSD", "Residérí")),
(mnem: "DVD", name: "Dívidere", sign: true, description: [
Integer part of the Euclidean division of two signed integers.
Will raise an arithmetic exception if the right operand is zero.
#aludoc("DVD", "04", "/", false, 1)
#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 right by a signed number.
Will raise an arithmetic exception if the right operand is negative.
#aludoc("DEM", "06", ">>", false, 1)
#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.
Will raise an arithmetic exception if the right operand is negative.
#aludoc("SIM", "07", "<<", false, 0)
#aludoc("SIM", "07", "<<", 0)
/ Instruction format: #amal
]),
], ..sized_also("SIM", "Ad Sinistró Movére")),
(
mnem: "ILG",
name: "Immediátum Legere",
@ -526,27 +489,27 @@ Common Notations:
]),
(mnem: "VEL", name: "Vel", description: [
Bitwise disjunction between two words.
#aludoc("VEL", [11], sym.or, true, 0)
#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",
@ -558,6 +521,7 @@ Common Notations:
#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",
@ -569,6 +533,7 @@ Common Notations:
#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: [
*Privileged* Halts the CPU.
@ -637,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).
],
),
)

55
editors/kak/a48s.kak Normal file
View 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...
}

View File

@ -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

View File

@ -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
View 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

View 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
View 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

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1,24 +0,0 @@
#include <common.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\nAvailable 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;
}
}