Microcode/ucode/sort4.uc
Gabriel Tofvesson 96f120a99d Simplify code
2019-05-07 17:28:34 +02:00

149 lines
3.7 KiB
Ucode

// Hi! If you're reading this, you probably want to know what this program does
// To that, I say: Good luck and I hope you have patience and a strong will to
// live, 'cause both will be negatively impacted by trying to read the code
// below.
// This isn't a joke; I feel like someone telling a person to get off the edge
// of a tall building here: reading the code below WILL negatively impact your
// life. You have been warned.
// For clarity's sake, I thought I'd add a small preface here:
// We use the optable as a replacement for a hashing algorithm. Check the
// #optable directives if you're wondering what bucket the 4 highest bits of a
// value end up pointing to. Each entry in the optable simply loads the
// address of the corresponding bucket and initiates an insertion sort for said
// bucket.
// Labels ending in "_SPEC" are edge-case optimization labels. They are
// branched to in the case of special edge cases with the idea being that they
// are much faster than following the reguar code-path (even if said path would
// ultimately perform the same action).
// For example, "call @JTABLE_SPEC" invokes a special jumptable subroutine
// which parallelizes some of the boilerplate needed for the upcoming merge.
#define LIST_START 0xE0
#define HIGHEST_BUCKET 0xD2
// Generate jump-table ;)
#emit
>for i in range(16): print("#optable "+hex(i)+" @OT_"+hex(i)[2::])
// Generate program memory:
// Addresses 0xE0-0xFF ignored
// Addresses that are a multiple of 0xE are set to 0
// All other addresses contain a relative pointer to the next bucket start
#pmgen if address < 0xE0: print(str(address)+" "+str(0 if (address % 14) == 0 else ((address - (address % 0xE)) - 0xE) if address > 0xD else -1))
// Set all GR-registers to -1, so that we always can call "sub gr" to increment
// AR, no matter what value we have in IR ;)
const 0xB00 // GRx=10, M=11
lsr; mov ar ir
lsr; reset gr
lsr; reset grm
mov ar ir // GRx=00, M=01
reset gr
reset grm
// Initialize PC to point at list
const LIST_START
mov ar pc
mov pc asr
// Perform bucketsort for 32 elements
#emit
>for i in range(31):
> print("mov pm ir; incpc; call @JTABLE")
mov pm ir; call @JTABLE_SPEC
// Initialize state for merge
const HIGHEST_BUCKET
mov ar asr
mov pm lc
sub gr
// Copy elements to list
$MERGE
mov ar asr; declc; bls @MB_SPEC
mov pm ir
mov pc asr // This branch improves stability
mov ir pm; incpc; bls @MERGE_BOTTOM // Transfer value and copy more elements
sub gr; bra @MERGE
$MERGE_BOTTOM
sub gr
mov ar asr
$MB_SPEC
mov pm ar; mov pm asr
sub gr
mov pm lc; bnz @MERGE
// Breakpoint hook and program termination point
$BREAK
$END
halt
// Jump-table subroutine
$JTABLE
mov pc hr; bop
$JTABLE_SPEC
const LIST_START
mov ar hr; bop
// Generate jump table
#emit
>bucket_size=14
>for i in range(16):
> print("$OT_"+hex(i)[2::])
> if i < 8:
> print("const "+str(bucket_size*(7-i)))
> else:
> print("const "+str(bucket_size*(23-i)))
> print("mov ar asr; bra @PREPARE_SORT")
// Actual bucketsort
$PREPARE_SORT
mov pm pc; mov pm lc // Load bucket length
sub gr; incpc // Increment bucket length
mov pc pm; bls @IE_SPEC // Store new length
mov ar pc; sub ar
sub ir // Save -IR into AR (you'll see why)
$INSERTION
mov pc asr; incpc; declc; bls @INSERTION_END_BIGGEST
add pm // Effectively, AR=PM-IR, except more like AR=-IR+PM
sub pm; brn @INSERTION
mov pm ar
mov ir pm; bls @IEN_SPEC
$INSERTION_SHIFT
mov pc asr
mov pm ir
mov ar pm; bls @INSERTION_END_NOTBIGGEST
mov ir ar; declc; incpc; bra @INSERTION_SHIFT
$IEN_SPEC
mov pc asr
mov ar pm; bra @INSERTION_END_NOTBIGGEST
$IE_SPEC
mov ar asr
$INSERTION_END_BIGGEST
mov ir pm
$INSERTION_END_NOTBIGGEST
mov hr pc
mov pc asr; ret