;   brainfuck_compiler_v1.asm - Brainfuck compiler for the 8086 employing some optimisations
;
;   This file is part of the 9086 project.
;
;   Copyright (c) 2024 Efthymios Kritikos
;
;   This program is free software: you can redistribute it and/or modify
;   it under the terms of the GNU General Public License as published by
;   the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.
;
;   This program is distributed in the hope that it will be useful,
;   but WITHOUT ANY WARRANTY; without even the implied warranty of
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;   GNU General Public License for more details.
;
;   You should have received a copy of the GNU General Public License
;   along with this program.  If not, see <http://www.gnu.org/licenses/>.

; 0x0000-0x0100 int vector 0x0100-0x0700 data 0x0700-0xC000 program data

mov sp,#STACK_COMPILER
mov bx,#bootup_msg
mov ah,#0x02
print1:
mov dl,[bx]
int #0x21
inc bx
cmp dl,#0x0A
jne print1

MOV DI,#0x0200
MOV AX,#0x0000
MOV bl,#0x00
CLEAR:
STOSW
INC BL
JNZ CLEAR

mov bx,#compiling
mov ah,#0x02
print2:
mov dl,[bx]
cmp dl,#0
je exit
int #0x21
inc bx
jmp print2
exit:

MOV SI,#prog
MOV DI,#0x0700
;CL: write concat   CH: move concat
MOV CX,#0
JMP COMPILE ; Moving some functions above the main switch to make shot jumps work


;;;;;;;;;   ]   ;;;;;;;;;
WAS_PR:
CALL FLUSH_MOVES
CALL FLUSH_WRITES

MOV AX,#0x078a ; mov (%bx),%al
STOSW

MOV AX,#0x003C ; cmp $0x0,%al
STOSW

MOV AX,#0x0574 ; je [after the absolute short jump instruction]
STOSW

MOV AL,#0xb8 ; [opcode only] mov 0x????,%ax
STOSB

POP BX
ADD BX,#4
MOV [DI],BX
INC DI
INC DI
SUB BX,#4

MOV AX,#0xE0FF ; jmp *%ax
STOSW

MOV [BX],DI

JMP COMPILE

;;;;;;;;;   [   ;;;;;;;;;
WAS_PL:
CALL FLUSH_MOVES

; optimise [-]
CMP WORD [SI],#0x5D2D
JNZ ACTUAL_LOOP
MOV CL,#0
INC SI
INC SI
MOV AX,#0x07C6
STOSW
MOV AL,#0
STOSB
JMP COMPILE


ACTUAL_LOOP:
CALL FLUSH_WRITES
MOV AX,#0x078a ; mov (%bx),%al
STOSW

MOV AX,#0x003c ; cmp $0x0,%al
STOSW

MOV AX,#0x0575 ; jne [after the absolute short jump instruction]
STOSW

MOV AL,#0xb8 ; [opcode only] mov 0x????,%ax
STOSB

PUSH DI

INC DI
INC DI

MOV AX,#0xe0ff ; jmp *%ax
STOSW

JMP COMPILE


;;;;;;;;;;;  ACTUAL START  ;;;;;;;;;;;;;;;
COMPILE:
MOV AL,[SI]
INC SI
CMP AL,#'+
JZ WAS_PLUS
CMP AL,#'-
JZ WAS_MINUS
CMP AL,#'>
JZ WAS_MR
CMP AL,#'<
JZ WAS_ML
CMP AL,#'[
JZ WAS_PL
CMP AL,#']
JZ WAS_PR
CMP AL,#'.
JZ WAS_PRINT

mov bx,#compiled
mov ah,#0x02
print3:
mov dl,[bx]
int #0x21
inc bx
cmp dl,#0x0A
jne print3

MOV AL,#0xF4 ; hlt
MOV [DI],AL
; From 0x100 its free but i'll do 0x200 in case it start writing earlier
MOV BX,#0x0200
MOV AX,#0x0700
JMP AX

;;;;;;;;;   .   ;;;;;;;;;
WAS_PRINT:
CALL FLUSH_MOVES
CALL FLUSH_WRITES

MOV AX,#0x02B4 ; mov $0x2,%ah
STOSW

MOV AX,#0x178A ; mov (%bx),%dl
STOSW

MOV AX,#0x21CD ; int $0x21
STOSW

JMP COMPILE
;;;;;;;;;   +   ;;;;;;;;;
WAS_PLUS:
CALL FLUSH_MOVES
INC CL
JMP COMPILE

;;;;;;;;;   -   ;;;;;;;;;
WAS_MINUS:
CALL FLUSH_MOVES
DEC CL
JMP COMPILE

;;;;;;;;;   >   ;;;;;;;;;
WAS_MR:
CALL FLUSH_WRITES
INC CH
JMP COMPILE

;;;;;;;;;   <   ;;;;;;;;;
WAS_ML:
CALL FLUSH_WRITES
DEC CH
JMP COMPILE



FLUSH_WRITES:
CMP CL,#0
JZ WRITES_FLUSHED
CMP CL,#1
JZ WRITES_ADD_ONE
CMP CL,#0xFF
JZ WRITES_DEC_ONE

;; General case
MOV AX,#0x0780 ; add %cl,(%bx)
STOSW
MOV AL,CL
STOSB
JMP WRITES_FLUSHED

WRITES_ADD_ONE:
MOV AX,#0x07fe ; incb (%bx)
STOSW
JMP WRITES_FLUSHED

WRITES_DEC_ONE:
MOV AX,#0x0ffe ; incb (%bx)
STOSW
JMP WRITES_FLUSHED

WRITES_FLUSHED:
MOV CL,#0
RET

FLUSH_MOVES:
CMP CH,#0
JZ MOVES_FLUSHED
CMP CH,#1
JZ MOVES_ONE_RIGHT
CMP CH,#0XFF
JZ MOVES_ONE_LEFT

;; General case
MOV AX,#0xC381 ; ADD $....,%bx
STOSW
MOV AL,CH
STOSB
TEST CH,#0x80
jz POSITIVE
MOV AL,#0xFF
STOSB
JMP MOVES_FLUSHED
POSITIVE:
MOV AL,#0x00
STOSB
JMP MOVES_FLUSHED

MOVES_ONE_RIGHT:
MOV AL,#0x43 ; inc %bx
STOSB
JMP MOVES_FLUSHED


MOVES_ONE_LEFT:
MOV AL,#0x4b ; dec %bx
STOSB
JMP MOVES_FLUSHED


MOVES_FLUSHED:
MOV CH,#0
RET

compiled: .ASCII '\rCompiled!   \n'
compiling: .ASCII 'Compiling...\0'
bootup_msg: .ASCII 'Native 8086 brainfuck compiler v1\n'
 .BLKB 6 ; Using the text as stack space for the compiled program
STACK_COMPILER: ; brainfuck_mandelbrot depends on stack being at the end
