Add sources

This commit is contained in:
luca0N! 2024-03-24 21:37:08 -03:00
parent f5934d26a3
commit 8117e581ea
Signed by: luca0N
GPG Key ID: 5978D960572B449E
5 changed files with 306 additions and 0 deletions

14
Makefile Normal file
View File

@ -0,0 +1,14 @@
# x86life: a life simulating game
# <https://git.luca0n.com/luca0N/x86life>
PROGRAM_NAME=x86life
ASM=nasm
.PHONY: clean
$(PROGRAM_NAME): src/life.asm src/commonio_read.asm src/commonio_write.asm
$(ASM) -f elf64 -g -F dwarf -o $(PROGRAM_NAME).o src/life.asm
$(LD) $(PROGRAM_NAME).o -o $(PROGRAM_NAME)
clean:
rm -fv $(PROGRAM_NAME) $(PROGRAM_NAME).o

35
src/commonio_read.asm Normal file
View File

@ -0,0 +1,35 @@
; x86life: a life simulating game
; Copyright (C) 2023-2024 luca0N!
;
; 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, version 3 of the License.
;
; 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 <https://www.gnu.org/licenses/>.
;
; <https://git.luca0n.com/luca0N/x86life>
; Contact: <https://www.luca0n.com/en/contact>
.read:
; read digit stdin
XOR RAX, RAX
XOR RDI, RDI
SYSCALL
; remove line feed, if present
DEC RAX
ADD RSI, RAX
CMP [RSI], BYTE 0x0A
JNE .read_ret
MOV [RSI], BYTE 0x00
.read_ret:
SUB RSI, RAX
RET
; vim: syntax=nasm ts=4 sw=4 et

36
src/commonio_write.asm Normal file
View File

@ -0,0 +1,36 @@
; x86life: a life simulating game
; Copyright (C) 2023-2024 luca0N!
;
; 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, version 3 of the License.
;
; 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 <https://www.gnu.org/licenses/>.
;
; <https://git.luca0n.com/luca0N/x86life>
; Contact: <https://www.luca0n.com/en/contact>
.print:
CALL .print_getLen
.printLen:
MOV RAX, 1
MOV RDI, 1
SYSCALL
RET
.print_getLen:
MOV RDX, RSI
.print_getLen_loop:
INC RDX
CMP [RDX], BYTE 0x00
JNE .print_getLen_loop
SUB RDX, RSI
RET
; vim: syntax=nasm ts=4 sw=4 et

158
src/life.asm Normal file
View File

@ -0,0 +1,158 @@
; x86life: a life simulating game
; Copyright (C) 2023-2024 luca0N!
;
; 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, version 3 of the License.
;
; 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 <https://www.gnu.org/licenses/>.
;
; <https://git.luca0n.com/luca0N/x86life>
; Contact: <https://www.luca0n.com/en/contact>
%include "src/commonio_write.asm"
%include "src/commonio_read.asm"
%include "src/printno.asm"
%define SYS_EXIT 60
%DEFINE PROTAGONIST_NAME_LEN 31
%DEFINE PROT_BUF_OFFSET_AGE 31
; The maximum age of the protagonist. Since we're using 7 bits for the age,
; this needs to be 127 (7Fh).
%DEFINE PROT_AGE_MAX 7Fh
SECTION .data
buf_protagonist: ; protagonist buffer. 31 bytes for
TIMES 32 DB 0 ; the name, 1 for age
buf_in: ; stdin buffer
TIMES 32 DB 0
buf_age:
TIMES 3 DB 0
SECTION .rodata
str_newln:
DB 0x0A, 0x00
str_intro:
DB "Welcome to Life!", 0x0A, "Insert the name of the ", \
"protagonist: ", 0x00
str_intro_name_invalid:
DB "The protagonist name must be within 1-32 boundaries.", \
0x0A, 0x00
str_game_dead:
DB "The protagonist has died at an age of: ", 0x00
str_birth:
DB "The protagonist was born today!", 0x0A, 0x00
str_birthday_1:
DB "Today, ", 0x00
str_birthday_2:
DB " turns ", 0x00
str_birthday_3:
DB "!", 0x0A, 0x00
str_continue:
DB "Press any key to age. ", 0x00
SECTION .text
GLOBAL _start
_start:
MOV RSI, str_intro ; print intro msg
CALL .print
MOV RSI, buf_protagonist ; read to buffer from stdin
MOV RDX, PROT_BUF_OFFSET_AGE
CALL .read
PUSH RAX
CMP RAX, 32 ; check whether the user send more
; data than the buffer could hold
JE .invalidNameBounds
POP RAX
CMP RAX, 2
JLE .invalidNameBounds
; Begin the game!!
MOV RSI, str_birth
CALL .print
.begin:
; Check whether the protagonist is still alive
; ============================================
; Alive/dead status is represented by the most
; significant bit in the age byte
MOV RAX, [buf_protagonist + PROT_BUF_OFFSET_AGE]
AND RAX, 80h
CMP RAX, 80h
JE .protDead
; Print age header
; ================
MOV RSI, str_birthday_1 ; "Today, "
CALL .print
MOV RSI, buf_protagonist ; (protagonist)
CALL .print
MOV RSI, str_birthday_2 ; " turns "
CALL .print
MOV RSI, buf_age ; (age)
MOV RAX, [buf_protagonist + PROT_BUF_OFFSET_AGE]
CALL .getHumanReadableNum ; (n)
MOV RSI, buf_age
MOV RDX, 3
CALL .printLen
MOV RSI, str_birthday_3 ; (!)
CALL .print
MOV RSI, str_continue
CALL .print
LEA RSI, [buf_protagonist + PROT_BUF_OFFSET_AGE]
MOV RAX, [RSI]
INC RAX
CMP RAX, PROT_AGE_MAX
JNE .begin_continue
OR RAX, 80h ; kill protagonist
.begin_continue:
MOV [RSI], RAX
MOV RSI, buf_in
MOV RDX, 1
CALL .read
JMP .begin
.protDead:
; Subroutine: the protagonist has died
; ====================================
MOV RSI, str_game_dead
CALL .print
MOV RSI, buf_age ; (age)
MOV RAX, [buf_protagonist + PROT_BUF_OFFSET_AGE]
AND RAX, 7Fh ; get rid of life bit
CALL .getHumanReadableNum
MOV RSI, buf_age
MOV RDX, 3
CALL .printLen
MOV RSI, str_newln
CALL .print
JMP .exit
.invalidNameBounds:
; MOV RSI, buf_protagonist
; CALL .read ; keep reading until there is nothing
; CMP RAX, 0 ; more to read to prevent pending data
; JNE .nameTooBig ; from going to the buffer
MOV RSI, str_intro_name_invalid
CALL .print
JMP _start
.exit:
MOV RAX, SYS_EXIT
XOR RDI, RDI
SYSCALL
; vim: syntax=nasm ts=4 sw=4 et

63
src/printno.asm Normal file
View File

@ -0,0 +1,63 @@
; x86life: a life simulating game
; Copyright (C) 2023-2024 luca0N!
;
; 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, version 3 of the License.
;
; 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 <https://www.gnu.org/licenses/>.
;
; <https://git.luca0n.com/luca0N/x86life>
; Contact: <https://www.luca0n.com/en/contact>
;SECTION .rodata
; num equ 20
;SECTION .data
; buf times 3 db 20h
;SECTION .text
; GLOBAL _start
.getHumanReadableNum:
; MOV AL, num ; put num on RAX
PUSH RAX ; save num on stack
MOV BL, 100 ; check for hundredth digit
DIV BL ; divide RAX by BL
CMP AL, 0
; MOV RSI, buf
ADD AL, 0x30 ; digit to ASCII
MOV [RSI], AL
SUB AL, 0x30
MUL BL ; multiply AL by BL
MOV BL, AL
POP RAX ; get original saved number
SUB AL, BL ; discard hundreds
PUSH RAX
MOV BL, 10
DIV BL ; get tenth digit
INC RSI ; next buffer byte
ADD AL, 0x30 ; digit to ASCII
MOV [RSI], AL
SUB AL, 0x30
MUL BL
MOV BL, AL
POP RAX
SUB AL, BL
INC RSI
ADD AL, 0x30
MOV [RSI], AL
SUB RSI, 2
RET
; vim: syntax=nasm ts=4 sw=4 et