Commit 56cb49ab authored by John P. Willis's avatar John P. Willis
Browse files

Clean up the CLI, add skeletal support for interrupts, begin work on supporting console input

parent 2f8a09a1
[console]
mode=serial
port=COM
port=/dev/ilxim
bps=9600
parity=N
data_bits=8
......
VM_OBJS = ilxi.o asm.o cpu.o error.o host.o storage.o lexer.o inst.o util.o bus.o console.o signal.o message.o profile.o config.o
XIASM_OBJS = xiasm.o asm.o cpu.o lexer.o storage.o inst.o error.o util.o console.o bus.o signal.o message.o profile.o config.o
FBCFLAGS = -g -mt
# -d STACKDEBUG
# -d LEXDEBUG
FBCFLAGS = -g -mt #-d STACKDEBUG -d INSTDEBUG #-d LEXDEBUG
all: vm assembler rom test
......
......@@ -228,6 +228,8 @@ function asm_encode_register(register_name as string) as ubyte
return NREG_SI
case "di"
return NREG_DI
case "bp"
return NREG_BP
case "ga"
return NREG_GA
case "gb"
......@@ -311,6 +313,8 @@ function asm_decode_register(reg as ubyte) as string
return "si"
case NREG_DI
return "di"
case NREG_BP
return "bp"
case NREG_GA
return "ga"
case NREG_GB
......
......@@ -43,15 +43,22 @@ end sub
sub bus_start()
if bus_started = 1 then exit sub
dim i as integer
for i = 1 to dev_count
message_print "bus_start(): starting device " & devices(i)
bus(devices(i)).dev_thread = threadcreate(bus(devices(i)).dev_cycle, @devices(i))
bus(devices(i)).dev_thread_started = 1
bus(devices(i)).dev_thread_started = 1
next i
message_print "bus_start(): waiting for bus quiescence"
sleep 500
bus_started = 1
end sub
sub bus_stop()
......@@ -71,6 +78,8 @@ sub bus_stop()
end if
next i
bus_started = 0
end sub
sub bus_sig_stop(device_number as ushort)
......
......@@ -31,6 +31,8 @@ dim shared io_ports(0 to IOPORT_COUNT - 1) as short
dim shared devices() as ubyte
dim shared dev_count as ubyte = 0
dim shared bus_started as ubyte = 0
declare sub bus_clear()
declare sub bus_init()
declare sub bus_start()
......
......@@ -156,12 +156,20 @@ sub console_cycle_serial(byval userdata as any ptr)
dim col as ubyte = 1 'x
dim row as ubyte = 1 'y
dim bytes_waiting as integer
dim input_buffer as string
do
bytes_waiting = lof(console_file_number)
if bytes_waiting > 0 then
message_print "console_cycle_serial(): reading " & bytes_waiting & " bytes from console"
input_buffer &= input(bytes_waiting, console_file_number)
end if
col = 1
row = 1
mutexlock console_mutex
for i = CONSOLE_OFFSET to CONSOLE_LIMIT - 1
c = st_read_byte(CONSOLE_PAGE, i)
......@@ -178,9 +186,7 @@ sub console_cycle_serial(byval userdata as any ptr)
end if
next i
mutexunlock console_mutex
sleep 25
sleep 25, 1
if bus_get_stop_flag(0) = 1 then exit do
loop
......
......@@ -10,9 +10,13 @@
#include "console.bi"
#include "bus.bi"
#include "signal.bi"
#include "error.bi"
#include "message.bi"
sub init_cpu()
interrupts_waiting = 0
redim interrupt_queue(0 to interrupts_waiting) as ubyte
with cpu_state
.pc = 0
......@@ -91,6 +95,14 @@ sub cpu()
' main cpu loop
do
#ifdef INSTDEBUG
message_print cpu_get_cppc() & " executing " & asm_disassemble(cpu_state.cp, cpu_state.pc)
#endif
if cpu_get_flag(FL_DEBUG) = 1 then
message_print cpu_get_cppc() & " " & asm_disassemble(cpu_state.cp, cpu_state.pc)
end if
inst_pc = cpu_state.pc
opcode = cpu_fetch()
......@@ -266,21 +278,27 @@ sub cpu()
cpu_state.es = 0
end if
if cpu_get_flag(FL_HALT) then exit do
if cpu_get_flag(FL_HALT) then
bus_stop
exit do
end if
cpu_process_interrupts
if cpu_get_flag(FL_DEBUG) then exit do
loop
bus_stop
if cpu_get_flag(FL_DEBUG) = 0 then
if cpu_state.es > 0 then
message_print "cpu(): trap at " & cpu_get_cppc()
message_print "cpu(): trap " & cpu_state.ec & " (severity " & cpu_state.es & ") at " & cpu_get_cppc() & " '" & error_string(cpu_state.ec) & "'"
message_print cpu_get_cppc() & " " & asm_disassemble(cpu_state.pc, cpu_state.pc)
else
message_print "cpu(): halt at " & cpu_get_cppc()
message_print "cpu(): halt at " & cpu_get_cppc()
end if
else
message_print cpu_get_cppc() & " " & asm_disassemble(cpu_state.cp, cpu_state.pc)
end if
end sub ' cpu()
......@@ -295,18 +313,21 @@ function cpu_fetch() as ubyte
end function ' cpu_fetch()
sub cpu_push_byte(byteval as ubyte)
st_write_byte cpu_state.sp, cpu_state.so, byteval
#ifdef STACKDEBUG
message_print "cpu_push_byte(): " & hex(byteval)
#endif
cpu_state.so -= 1
cpu_state.so -= 1
st_write_byte cpu_state.sp, cpu_state.so, byteval
end sub ' cpu_push_byte()
function cpu_pop_byte() as ubyte
dim retval as ubyte
dim retval as ubyte
retval = st_read_byte(cpu_state.sp, cpu_state.so)
cpu_state.so += 1
......@@ -318,27 +339,29 @@ function cpu_pop_byte() as ubyte
end function ' cpu_pop_byte()
sub cpu_push_word(wordval as ushort)
st_write_word cpu_state.sp, cpu_state.so - 1, wordval
#ifdef STACKDEBUG
locate 30,1
message_print "cpu_push_word(): " & hex(wordval)
#endif
cpu_state.so -= 1
cpu_state.so -= 2
st_write_word cpu_state.sp, cpu_state.so, wordval
end sub ' cpu_push_word()
function cpu_pop_word() as ushort
dim retval as ushort
retval = st_read_word(cpu_state.sp, cpu_state.so)
cpu_state.so += 2
#ifdef STACKDEBUG
locate 30,1
message_print "cpu_pop_word(): " & hex(retval)
#endif
#endif
return retval
cpu_state.so += 2
end function ' cpu_pop_word()
sub cpu_dump_state()
......@@ -353,7 +376,7 @@ sub cpu_dump_state()
print ""
print "PC "; ilxi_pad_left(hex(x.pc),"0",4), "EC "; ilxi_pad_left(hex(x.ec),"0",4), "ES "; ilxi_pad_left(hex(x.es),"0",4), "CP "; ilxi_pad_left(hex(x.cp),"0",4), "DP "; ilxi_pad_left(hex(x.dp),"0",4)
print "EP "; ilxi_pad_left(hex(x.ep),"0",4), "SP "; ilxi_pad_left(hex(x.sp),"0",4), "SO "; ilxi_pad_left(hex(x.so),"0",4), "FL "; ilxi_pad_left(hex(x.fl),"0",4), "SS "; ilxi_pad_left(hex(x.ss),"0",4)
print "DS "; ilxi_pad_left(hex(x.ds),"0",4), "SI "; ilxi_pad_left(hex(x.ds),"0",4), "DI "; ilxi_pad_left(hex(x.di),"0",4)
print "DS "; ilxi_pad_left(hex(x.ds),"0",4), "SI "; ilxi_pad_left(hex(x.ds),"0",4), "DI "; ilxi_pad_left(hex(x.di),"0",4), "BP "; ilxi_pad_left(hex(x.bp),"0",4)
print ""
print "GA "; ilxi_pad_left(hex(x.ga),"0",4), "GB "; ilxi_pad_left(hex(x.gb),"0",4), "GC "; ilxi_pad_left(hex(x.gc),"0",4), "GD "; ilxi_pad_left(hex(x.gd),"0",4), "GE "; ilxi_pad_left(hex(x.ge),"0",4)
print "GF "; ilxi_pad_left(hex(x.gf),"0",4), "GG "; ilxi_pad_left(hex(x.gg),"0",4), "GH "; ilxi_pad_left(hex(x.gh),"0",4), "GI "; ilxi_pad_left(hex(x.gi),"0",4), "GJ "; ilxi_pad_left(hex(x.gj),"0",4)
......@@ -427,6 +450,8 @@ sub cpu_set_reg_alpha(register as string, value as ushort)
cpu_state.si = value
case REG_DI
cpu_state.di = value
case REG_BP
cpu_state.bp = value
case REG_GA
cpu_state.ga = value
case REG_GB
......@@ -515,6 +540,8 @@ function cpu_get_reg_alpha(register as string) as ushort
return cpu_state.si
case REG_DI
return cpu_state.di
case REG_BP
return cpu_state.bp
case REG_GA
return cpu_state.ga
case REG_GB
......@@ -603,6 +630,8 @@ sub cpu_set_reg(register as ubyte, value as ushort)
cpu_state.si = value
case NREG_DI
cpu_state.di = value
case NREG_BP
cpu_state.bp = value
case NREG_GA
cpu_state.ga = value
case NREG_GB
......@@ -692,6 +721,8 @@ function cpu_get_reg(register as ubyte) as ushort
return cpu_state.si
case NREG_DI
return cpu_state.di
case NREG_BP
return cpu_state.bp
case NREG_GA
return cpu_state.ga
case NREG_GB
......@@ -749,4 +780,26 @@ function cpu_get_reg(register as ubyte) as ushort
end select
end function ' cpu_get_reg()
\ No newline at end of file
end function ' cpu_get_reg()
sub cpu_queue_interrupt(interrupt_number as ubyte)
interrupts_waiting += 1
redim preserve interrupt_queue(0 to interrupts_waiting) as ubyte
interrupt_queue(interrupts_waiting) = interrupt_number
end sub ' cpu_queue_interrupt()
sub cpu_process_interrupts()
dim i as integer
for i = 1 to interrupts_waiting
message_print "cpu_process_interrupts(): dispatching interrupt " & trim(str(interrupt_queue(i)))
next i
interrupts_waiting = 0
redim interrupt_queue(0 to interrupts_waiting) as ubyte
end sub ' cpu_process_interrupts()
......@@ -143,6 +143,8 @@
#define REG_SI "si"
#define REG_DI "di"
#define REG_BP "bp"
#define REG_GA "ga"
#define REG_GB "gb"
#define REG_GC "gc"
......@@ -194,6 +196,8 @@
#define NREG_SI 27
#define NREG_DI 28
#define NREG_BP 30
#define NREG_GA 40
#define NREG_GB 41
#define NREG_GC 42
......@@ -280,6 +284,8 @@ type t_cpu_state
si as ushort 'source index
di as ushort 'dest index
bp as ushort 'base pointer
ga as ushort 'general a
gb as ushort 'general b
gc as ushort 'general c
......@@ -298,18 +304,11 @@ type t_cpu_state
gp as ushort 'general p
end type
type t_instruction
opcode as byte
src_amod as byte
src_bytecount as byte
src_address(256) as byte
dst_amod as byte
dst_bytecount as byte
dst_address(256) as byte
end type
common shared cpu_state as t_cpu_state
dim shared interrupt_queue() as ubyte
dim shared interrupts_waiting as integer
declare sub init_cpu()
declare function cpu_get_cppc() as string
declare sub cpu()
......@@ -327,4 +326,6 @@ declare function cpu_get_reg(register as ubyte) as ushort
declare sub cpu_push_byte(byteval as ubyte)
declare function cpu_pop_byte() as ubyte
declare sub cpu_push_word(wordval as ushort)
declare function cpu_pop_word() as ushort
\ No newline at end of file
declare function cpu_pop_word() as ushort
declare sub cpu_queue_interrupt(interrupt_number as ubyte)
declare sub cpu_process_interrupts()
\ No newline at end of file
......@@ -15,4 +15,23 @@ sub machine_error(error_code as integer, severity as integer)
cpu_set_flag FL_HALT
end if
end sub
\ No newline at end of file
end sub
function error_string(error_code as integer) as string
select case error_code
case ERR_INVALID_PAGE_ID
return "invalid memory access (page out of bounds)"
case ERR_INVALID_OFFSET
return "invalid memory access (offset out of bounds)"
case ERR_DIVZERO
return "division by zero"
case ERR_INVALID_IOPORT
return "invalid I/O port"
case ERR_INVALID_DATA_TYPE
return "invalid data type in instruction operand"
end select
return "invalid error code"
end function
\ No newline at end of file
......@@ -23,4 +23,5 @@
'
#define ERR_INVALID_DATA_TYPE 151
declare sub machine_error(error_code as integer, severity as integer)
\ No newline at end of file
declare sub machine_error(error_code as integer, severity as integer)
declare function error_string(error_code as integer) as string
\ No newline at end of file
......@@ -84,7 +84,7 @@ sub cli()
end if
st_save_page img_file, page_index
case "assemble"
case "assemble", "a"
dim le_origin as lexer_entry
dim origin_addr as ushort
......@@ -116,10 +116,14 @@ sub cli()
asm_disassemble_range page_addr, start_offset_addr, da_count
case "step"
cpu_clear_flag FL_DEBUG
cpu_set_flag FL_DEBUG
cpu
case "step"
if cpu_get_flag(FL_HALT) = 0 then
if cpu_get_flag(FL_DEBUG) = 0 then cpu_set_flag FL_DEBUG
cpu
else
message_print "cli(): CPU is halted. Type 'reset' at the prompt before attempting 'step'."
end if
case "getr"
ilxi_getr get_lexer_entry(1).strval
case "setr"
......@@ -217,8 +221,12 @@ sub cli()
case "ver"
print "ILXI 0.1"
case "run"
cpu_clear_flag FL_DEBUG
cpu
if cpu_get_flag(FL_HALT) = 0 then
cpu_clear_flag FL_DEBUG
cpu
else
message_print "cli(): CPU is halted. Type 'reset' at the prompt before attempting 'run'."
end if
case "reset"
init_cpu
case "exit"
......@@ -231,7 +239,7 @@ sub cli()
end sub
sub ilxi_getr(register as string)
message_print ucase(register) & ": " & trim(str(cpu_get_reg_alpha(lcase(register))))
message_print ucase(register) & ": " & trim(hex(cpu_get_reg_alpha(lcase(register))))
end sub
sub ilxi_setr(register as string, value as integer)
......
......@@ -9,13 +9,14 @@
#include "ilxi.bi"
#include "error.bi"
#include "bus.bi"
#include "message.bi"
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
case NREG_LA, NREG_LB, NREG_LC, NREG_LD, NREG_LE, NREG_HA, NREG_HB, NREG_HC, NREG_HD, NREG_HE
return cubyte(cpu_get_reg(op.low_byte))
case else
machine_error ERR_INVALID_DATA_TYPE, 10
......@@ -34,6 +35,12 @@ function inst_getbyte(op as t_operand, page as integer) as ubyte
return st_read_byte(page, ptr_val + op.displacement)
end if
elseif op.immediate = 1 then
#ifdef INSTDEBUG
message_print "inst_getbyte(): immediate " & hex(op.low_byte)
#endif
return op.low_byte
end if
......@@ -45,7 +52,7 @@ function inst_getword(op as t_operand, page as integer) as ushort
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
case NREG_LA, NREG_LB, NREG_LC, NREG_LD, NREG_LE, NREG_HA, NREG_HB, NREG_HC, NREG_HD, NREG_HE
machine_error ERR_INVALID_DATA_TYPE, 10
case else
return cpu_get_reg(op.low_byte)
......@@ -70,11 +77,12 @@ end function ' inst_getword()
sub inst_setbyte(op as t_operand, page as integer, value 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
case NREG_LA, NREG_LB, NREG_LC, NREG_LD, NREG_LE, NREG_HA, NREG_HB, NREG_HC, NREG_HD, NREG_HE
cpu_set_reg op.low_byte, value
case else
machine_error ERR_INVALID_DATA_TYPE, 10
......@@ -101,13 +109,11 @@ end sub ' inst_setbyte()
sub inst_setword(op as t_operand, page as integer, value as ushort)
print "inst_setword(): "; value
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
case NREG_LA, NREG_LB, NREG_LC, NREG_LD, NREG_LE, NREG_HA, NREG_HB, NREG_HC, NREG_HD, NREG_HE
machine_error ERR_INVALID_DATA_TYPE, 10
exit sub
case else
......@@ -388,6 +394,9 @@ sub inst_shl(dest as t_operand, count as t_operand)
end if
inst_setbyte dest, cpu_state.dp, cubyte(result)
if a2 >= 8 then cpu_set_flag FL_OVERFLOW
case DT_WORD
a1 = inst_getword(dest, cpu_state.dp)
a2 = inst_getword(count, cpu_state.dp)
......@@ -399,10 +408,13 @@ sub inst_shl(dest as t_operand, count as t_operand)
end if
inst_setword dest, cpu_state.dp, cushort(result)
if a2 >= 16 then cpu_set_flag FL_OVERFLOW
end select
if result = 0 then cpu_set_flag FL_ZERO
end sub ' inst_shl()
sub inst_shr(dest as t_operand, count as t_operand)
......@@ -432,6 +444,9 @@ sub inst_shr(dest as t_operand, count as t_operand)
end if
inst_setbyte dest, cpu_state.dp, cubyte(result)
if a2 >= 8 then cpu_set_flag FL_OVERFLOW
case DT_WORD
a1 = inst_getword(dest, cpu_state.dp)
a2 = inst_getword(count, cpu_state.dp)
......@@ -443,6 +458,8 @@ sub inst_shr(dest as t_operand, count as t_operand)
end if
inst_setword dest, cpu_state.dp, cushort(result)
if a2 >= 16 then cpu_set_flag FL_OVERFLOW
end select
if result = 0 then cpu_set_flag FL_ZERO
......@@ -713,11 +730,20 @@ sub inst_icall(dest as t_operand)
exit sub
end if
cpu_queue_interrupt inst_getbyte(dest, cpu_state.dp)
end sub ' inst_icall()
sub inst_sret()
cpu_state.pc = cpu_pop_word()
dim new_pc as ushort = cpu_pop_word()
#ifdef INSTDEBUG
message_print "inst_sret(): returning to " & hex(new_pc)
#endif
cpu_state.pc = new_pc
end sub ' inst_sret()
sub inst_lret()
......@@ -797,4 +823,4 @@ end sub ' inst_out()
sub inst_hlt()
cpu_set_flag FL_HALT
end sub ' inst_hlt()
\ No newline at end of file
end sub ' inst_hlt()
......@@ -4,6 +4,8 @@
#include "message.bi"
#include "console.bi"
#include "cpu.bi"
#include "asm.bi"
sub message_init()
......
#!/bin/bash
sudo socat -d -d pty,raw,echo=0,link=/dev/ilximcon pty,raw,echo=0,link=/dev/modem &
sudo chmod 777 /dev/pts/*
......@@ -40,10 +40,7 @@ LABEL __rom_init
SCALL WORD {__term_print_string}
;;
;; HALT
;;
HLT
BRANCH WORD {__rom_init}
;; __term_print_string
;;
......@@ -52,9 +49,12 @@ LABEL __term_print_string
;;
;; PRESERVE REGISTERS
;;
;PUSH WORD %SS
;PUSH WORD %DS
;PUSH WORD %DI
PUSH WORD %BP
COPY WORD %BP,%SO
PUSH WORD %SS
PUSH WORD %DS
PUSH WORD %DI
COPY WORD %DS,{VID_PAGE}
COPY WORD %DI,#{TERM_PTR}
......@@ -66,9 +66,11 @@ LABEL __term_print_string
;;
;; RESTORE REGISTERS AND RETURN
;;
;POP WORD %DI
;POP WORD %DS
;POP WORD %SS
POP WORD %DI
POP WORD %DS
POP WORD %SS
POP WORD %BP
SRET
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment