Commit e7fe1692 authored by John P. Willis's avatar John P. Willis

External assembler and CMPSZ instruction working

parent 8b2956f4
VM_OBJS = ilxi.o alu.o asm.o cpu.o error.o host.o storage.o lexer.o inst.o util.o
XIASM_OBJS = xiasm.o asm.o cpu.o lexer.o storage.o inst.o error.o util.o
VM_OBJS = ilxi.o alu.o asm.o cpu.o error.o host.o storage.o lexer.o inst.o util.o console.o
XIASM_OBJS = xiasm.o asm.o cpu.o lexer.o storage.o inst.o error.o util.o console.o
FBCFLAGS = -g
#-d LEXDEBUG
......@@ -24,6 +24,9 @@ alu.o: alu.bas
asm.o: asm.bas
fbc $(FBCFLAGS) -o asm.o -c asm.bas
console.o: console.bas
fbc $(FBCFLAGS) -o console.o -c console.bas
cpu.o: cpu.bas
fbc $(FBCFLAGS) -o cpu.o -c cpu.bas
......
......@@ -370,6 +370,8 @@ function asm_encode_opcode(instruction as string) as ubyte
select case lcase(instruction)
case "copy", "copy"
return OP_COPY
case "cpsz"
return OP_CPSZ
case "add", "add"
return OP_ADD
case "sub", "sub"
......@@ -394,6 +396,8 @@ function asm_encode_opcode(instruction as string) as ubyte
return OP_EQV
case "cmp"
return OP_CMP
case "cmpsz"
return OP_CMPSZ
case "branch"
return OP_BRANCH
case "beq"
......@@ -433,6 +437,8 @@ function asm_decode_opcode(opcode as ubyte) as string
select case opcode
case OP_COPY
return "copy"
case OP_CPSZ
return "cpsz"
case OP_ADD
return "add"
case OP_SUB
......@@ -457,6 +463,8 @@ function asm_decode_opcode(opcode as ubyte) as string
return "eqv"
case OP_CMP
return "cmp"
case OP_CMPSZ
return "cmpsz"
case OP_BRANCH
return "branch"
case OP_BEQ
......@@ -559,7 +567,7 @@ function asm_operand_count(opcode as ubyte) as ubyte
return 2
case OP_BEQ, OP_BNE, OP_BZ, OP_BLT, OP_BGT
return 1
case OP_SRET, OP_LRET, OP_IRET, OP_NOP, OP_HLT
case OP_SRET, OP_LRET, OP_IRET, OP_NOP, OP_HLT, OP_CPSZ, OP_CMPSZ
return 0
end select
end function ' asm_operand_count()
......
'
' console.bas
'
#include "console.bi"
#include "storage.bi"
sub console_refresh()
dim i as integer
dim c as ubyte
dim col as ubyte = 1 'x
dim row as ubyte = 1 'y
for i = CONSOLE_OFFSET to CONSOLE_LIMIT - 1
c = st_read_byte(CONSOLE_PAGE, i)
locate row, col, 0: print chr(c);
if col >= CONSOLE_WIDTH then
row = row + 1
col = 1
else
col = col + 1
end if
next i
end sub
\ No newline at end of file
#define CONSOLE_PAGE &H0001
#define CONSOLE_OFFSET &H0000
#define CONSOLE_LIMIT &H07D0
#define CONSOLE_WIDTH 80
#define CONSOLE_HEIGHT 25
declare sub console_refresh()
\ No newline at end of file
......@@ -7,11 +7,12 @@
#include "asm.bi"
#include "util.bi"
#include "inst.bi"
#include "console.bi"
sub init_cpu()
with cpu_state
.pc = 0
.pc = 1
.ec = 0
.es = 0
......@@ -21,7 +22,7 @@ sub init_cpu()
.dp = 0
.ep = 0
.sp = 0
.so = PAGESIZE - 1
.so = PAGESIZE - 2
.ss = 0
.ds = 0
......@@ -46,10 +47,15 @@ sub init_cpu()
.go = 0
.gp = 0
end with
cpu_set_flag FL_INTERRUPT
st_load_page "rom.bin", 0
end sub
sub cpu()
dim clock_count as long = 0
dim opcode as ubyte
dim inst_pc as ushort
......@@ -62,9 +68,17 @@ sub cpu()
dim data_type as ubyte
cpu_clear_flag FL_HALT
cls
' main cpu loop
do
clock_count += 1
if clock_count = 100 then
console_refresh
clock_count = 0
end if
inst_pc = cpu_state.pc
if cpu_get_flag(FL_DEBUG) then
......@@ -166,6 +180,8 @@ sub cpu()
select case opcode
case OP_COPY
inst_copy operands(1), operands(2)
case OP_CPSZ
inst_cpsz
case OP_ADD
inst_add operands(1), operands(2)
case OP_SUB
......@@ -190,6 +206,8 @@ sub cpu()
inst_eqv operands(1), operands(2)
case OP_CMP
inst_cmp operands(1), operands(2)
case OP_CMPSZ
inst_cmpsz
case OP_BRANCH
inst_branch operands(1)
case OP_BEQ
......@@ -241,11 +259,16 @@ sub cpu()
end if
if cpu_get_flag(FL_HALT) then
console_refresh
if cpu_state.es > 0 then
print ""
print "cpu(): trap "; trim(str(cpu_state.ec)); " at pc = "; trim(str(cpu_state.pc))
else
print ""
print "cpu(): halt at "; ilxi_pad_left(hex(cpu_state.cp), "0", 4); ":"; ilxi_pad_left(hex(inst_pc), "0", 4)
end if
end if
exit do
end if
......@@ -254,7 +277,6 @@ sub cpu()
loop
end sub ' cpu()
function cpu_fetch() as ubyte
......
......@@ -57,6 +57,7 @@
#define OP_DATA 000
#define OP_COPY 001
#define OP_CPSZ 002
#define OP_ADD 003
#define OP_SUB 004
#define OP_MUL 005
......@@ -69,6 +70,7 @@
#define OP_XOR 012
#define OP_EQV 013
#define OP_CMP 014
#define OP_CMPSZ 015
#define OP_BRANCH 020
#define OP_BEQ 021
......
......@@ -8,11 +8,15 @@
#include "storage.bi"
#include "asm.bi"
#include "util.bi"
#include "console.bi"
startup
sub startup()
color 7,0
color 12,0: color 7,0 ' hack to get around weird terminal bug around 7 being the default
cls
print "ILXIM Virtual Machine"
print " Copyright (C) 2015 Coherent Logic Development LLC"
print ""
......@@ -39,6 +43,8 @@ sub cli()
cmd_name = get_lexer_entry(0).strval
select case cmd_name
case "redraw"
cls: console_refresh
case "loadpage", "lp"
dim img_file as string = get_lexer_entry(1).strval
dim page_index as integer
......
......@@ -13,7 +13,6 @@ function inst_getbyte(op as t_operand, page as integer) as ubyte
if op.register = 1 then
if op.indirect = 0 then 'register direct
select case op.low_byte
case NREG_LA, NREG_LB, NREG_LC, NREG_LC, NREG_LD, NREG_LE, NREG_HA, NREG_HB, NREG_HC, NREG_HD, NREG_HE
return cubyte(cpu_get_reg(op.low_byte))
......@@ -155,6 +154,26 @@ sub inst_copy(dest as t_operand, source as t_operand)
end sub ' inst_copy()
sub inst_cpsz()
' copy ZSTRING from SS:SI to DS:DI
dim sb as ubyte
do
sb = st_read_byte(cpu_state.ss, cpu_state.si)
if sb <> 0 then
st_write_byte cpu_state.ds, cpu_state.di, sb
cpu_state.si += 1
cpu_state.di += 1
else
exit sub
end if
loop
end sub ' inst_cpsz()
sub inst_add(dest as t_operand, source as t_operand)
' cannot store a result in an immediate value
......@@ -308,6 +327,10 @@ sub inst_cmp(dest as t_operand, source as t_operand)
end sub ' inst_cmp()
sub inst_cmpsz()
end sub ' inst_cmpsz()
sub inst_branch(dest as t_operand)
select case dest.data_type
case DT_BYTE
......
......@@ -5,6 +5,7 @@
#include once "asm.bi"
declare sub inst_copy(dest as t_operand, source as t_operand)
declare sub inst_cpsz()
declare sub inst_add(dest as t_operand, source as t_operand)
declare sub inst_sub(dest as t_operand, source as t_operand)
declare sub inst_mul(dest as t_operand, source as t_operand)
......@@ -17,6 +18,7 @@ declare sub inst_and(dest as t_operand, source as t_operand)
declare sub inst_xor(dest as t_operand, source as t_operand)
declare sub inst_eqv(dest as t_operand, source as t_operand)
declare sub inst_cmp(dest as t_operand, source as t_operand)
declare sub inst_cmpsz()
declare sub inst_branch(dest as t_operand)
declare sub inst_beq(dest as t_operand)
declare sub inst_bne(dest as t_operand)
......
......@@ -3,71 +3,74 @@
;
; ILXI ROM
;
ORIGIN MAIN
PROGRAM SEGMENT CODE "ROMCODE.BIN"
SYMBOL ZSTRING NAME "ILXIM ROM Monitor"
SYMBOL WORD VID_PAGE 3
SYMBOL WORD VID_OFFSET 0
LABEL MAIN
;
; main entry point
;
push %ep
push %ga
push %gb
push %gc
copy %ga,{NAME}
copy %ep,{VID_PAGE}
copy %gb,{VID_OFFSET}
scall {STRCPY}
pop %gc
pop %gb
pop %ga
pop %ep
hlt
LABEL STRCPY
;
; STRCPY
; DP:GA source
; EP:GB target
;
LABEL STRCPY_TOP
; copy the source byte to %gc
copy %gc,(%ga)
; exit if null byte encountered
cmp %gc,0
beq {STRCPY_END}
; save dp and set dp = ep
push %dp
copy %dp,%ep
; copy %gc to the target
copy (%gb),%gc
; Copyright (C) 2015 Coherent Logic Development LLC
;
pop %dp
PROGRAM TITLE 'ROM'
ORIGIN 1 ; ROM CODE BEGINS AT 0000:0001
add %ga,1
add %gb,1
branch {STRCPY_TOP}
LABEL STRCPY_END
; return
lret
EQU VID_PAGE 1 ; VIDEO BUFFER IS AT 0001:0000 - 0001:07D0
EQU VID_BASE 0 ; VIDEO BUFFER BASE OFFSET
EQU ROM_DATA_PAGE 0
EQU ROM_STACK 10 ; ROM RESERVES PAGE 10 FOR STACK OPERATIONS
LABEL __rom_start
;;
;; JUMP TO ROM INITIALIZATION ROUTINE
;;
BRANCH WORD {__rom_init}
;; DEFINES
VAR ZSTRING ROM_VS "ILXI ROM MONITOR V0.01 COPYRIGHT (C) 2015 COHERENT LOGIC DEVELOPMENT LLC"
VAR WORD TERM_PTR 1
LABEL __rom_init
;;
;; SET UP DATA AND STACK
;;
COPY WORD %DP,{ROM_DATA_PAGE}
COPY WORD %SP,{ROM_STACK}
;;
;; PRINT ROM VERSION
;;
COPY WORD %SS,%DP
COPY WORD %SI,{ROM_VS}
SCALL WORD {__term_print_string}
;;
;; HALT
;;
HLT
;; __term_print_string
;;
;; PRINTS STRING AT SS:SI
LABEL __term_print_string
;;
;; PRESERVE REGISTERS
;;
PUSH WORD %SS
PUSH WORD %DS
PUSH WORD %DI
COPY WORD %DS,{VID_PAGE}
COPY WORD %DI,#{TERM_PTR}
CPSZ
ADD WORD (#{TERM_PTR}),%DI
;;
;; RESTORE REGISTERS AND RETURN
;;
POP WORD %DI
POP WORD %DS
POP WORD %SS
SRET
;
; termfill.xa
;
; Test program to fill screen with letters
;
PROGRAM TITLE 'TERMFILL'
ORIGIN 256
EQU OUT_CHAR 65 ; the letter 'A'
EQU VID_PAGE 1 ; video segment
EQU VID_BASE 0 ; video offset
EQU CHAR_COUNT 2000 ; characters to be output
LABEL MAIN
COPY WORD %DS,{VID_PAGE} ; set dest. segment to video segment
COPY BYTE %LA,{OUT_CHAR} ; put OUT_CHAR in low byte of %GA
COPY WORD %GC,{VID_BASE} ; initialize counter
LABEL NEXT
COPY BYTE (%GC),%LA ; copy character to next slot in memory
CMP WORD %GC,{CHAR_COUNT} ; see if we have already reached the maximum char count
BEQ WORD {MAIN_tail} ; if we do, jump out of the loop
ADD WORD %GC,1 ; else, increment counter
BRANCH WORD {NEXT} ; and do it again
LABEL MAIN_tail
HLT
\ No newline at end of file
......@@ -11,6 +11,8 @@
#include "lexer.bi"
#include "util.bi"
#include "xiasm.bi"
#include "console.bi"
#include "cpu.bi"
sub main(args as string)
......@@ -27,12 +29,45 @@ sub main(args as string)
end sub
sub do_asm(filename as string)
sub do_asm(filename as string, argi as integer)
dim output_file_name as string
dim line_count as integer = read_source_file(filename)
st_save_page output_file_name, 0
initial_pass argi
if udidx > 0 then ' we have a need for a fix-up pass
print ">>> PASS 2 [INFO]: Attempting to resolve "; trim(str(udidx)); " symbol(s) left over from pass 1"
dim i as integer
dim e as undef_entry
dim f as symtab_entry
dim fixup_offset as ushort
for i = 1 to udidx
e = udtab(i)
fixup_offset = e.byte_offset
f = lookup_symbol(e.e_key)
if f.resolved = 0 then
print ">>> PASS 2 [FATAL]: Unresolved symbol "; e.e_key
end
else
print ">>> PASS 2 [INFO]: Resolved symbol "; e.e_key; " (symbol found at offset "; hex(f.offset); "h, inserted at fix-up offset "; hex(fixup_offset); "h)"
st_write_word argi, fixup_offset, f.offset
end if
next i
end if
output_file_name = left(filename, instrrev(filename, ".") - 1) & ".bin"
st_save_page output_file_name, argi
end sub
......@@ -77,28 +112,47 @@ function read_source_file(filename as string) as integer
end function
function pass(pass_number as integer) as byte
sub initial_pass(page_number as ushort)
dim arg_count as integer = 0
dim cur_arg as string
dim t_sym as symtab_entry
dim i as integer
cpu_state.ep = page_number
for i = 1 to ubound(input_lines)
t_sym.resolved = 0
arg_count = lex(input_lines(i))
cur_arg = get_lexer_entry(0).strval
select case cur_arg
case "PROGRAM"
case "ORIGIN"
case "PROGRAM"
output_file_name = get_lexer_entry(3).strval
case "SYMBOL"
if get_lexer_entry(1).lexer_class = LC_BYTE then
asm_offset = get_lexer_entry(1).byteval
else
asm_offset = get_lexer_entry(1).intval
end if
print ">>> PASS 1 [INFO]: Program ORIGIN set to offset "; hex(asm_offset)
case "EQU"
t_sym.e_key = get_lexer_entry(1).strval
t_sym.e_class = SYMCLASS_EQU
t_sym.strval = get_lexer_entry(2).strval
t_sym.resolved = 1
install_symbol t_sym
case "VAR"
t_sym.e_key = get_lexer_entry(2).strval
t_sym.e_type = get_lexer_entry(1).strval
t_sym.e_class = SYMCLASS_VAR
t_sym.offset = asm_offset
t_sym.resolved = 1
select case t_sym.e_type
case "ZSTRING"
dim j as integer
......@@ -108,7 +162,6 @@ function pass(pass_number as integer) as byte
for j = 1 to len(get_lexer_entry(3).strval)
b = asc(mid(get_lexer_entry(3).strval, j, 1))
st_write_byte 0, asm_offset, b
......@@ -119,31 +172,40 @@ function pass(pass_number as integer) as byte
t_sym.strval = get_lexer_entry(3).strval
case "WORD"
' st_write_byte 0, asm_offset,
t_sym.byteval = get_lexer_entry(3).byteval
st_write_word page_number, asm_offset, t_sym.wordval
asm_offset += 2
case "BYTE"
t_sym.byteval = get_lexer_entry(3).byteval
t_sym.offset = asm_offset
st_write_byte 0, asm_offset, t_sym.byteval
st_write_byte page_number, asm_offset, t_sym.byteval
asm_offset += 1
end select
install_symbol t_sym
case "LABEL"
t_sym.e_key = get_lexer_entry(1).strval
t_sym.e_type = "LABEL"
t_sym.e_class = SYMCLASS_LABEL
t_sym.offset = asm_offset
t_sym.resolved = 1
install_symbol t_sym
case else
dim ts as string
fixup_flag = 0
ts = expand_macros(input_lines(i))
print ilxi_pad_left(hex(asm_offset), "0", 4); ": "; ts
print ">>> PASS 1 [OUTPUT]: "; ilxi_pad_left(hex(asm_offset), "0", 4); ": "; ts
asm_assemble ts
asm_offset += 1
if fixup_flag = 1 then udtab(udidx).byte_offset = asm_offset - 2
end select
next i
end function
end sub ' initial_pass()
sub install_symbol(sym_entry as symtab_entry)
stidx += 1
......@@ -160,11 +222,27 @@ function lookup_symbol(key as string) as symtab_entry
next i
dim tmp as symtab_entry
tmp.offset = -1
tmp.resolved = 0
tmp.e_class = SYMCLASS_LABEL 'what a hack...
return tmp
end function
sub install_undef(uent as undef_entry)
udidx += 1
redim preserve udtab(udidx) as undef_entry
udtab(udidx) = uent
end sub
function lookup_undef(key as string) as undef_entry
dim i as integer
for i = 1 to udidx
next
end function
function expand_macros(input_string as string) as string
dim macro_name as string
......@@ -176,39 +254,65 @@ function expand_macros(input_string as string) as string
dim symbol as symtab_entry
dim in_macro as ubyte = 0
dim in_label as ubyte = 0
dim in_macro as ubyte = 0
for i = 1 to len(input_string)
c = mid(input_string, i, 1)
select case c
case "["
in_label = 1
case "]"
in_label = 0
symbol = lookup_symbol(label_name)
case "{"