URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/eco32/tags/eco32-0.25/monitor/monitor
- from Rev 242 to Rev 248
- ↔ Reverse comparison
Rev 242 → Rev 248
/boards/s3e-500/start.s
0,0 → 1,496
; |
; start.s -- ECO32 ROM monitor startup and support routines |
; |
|
.set BIO_BASE,0xF1000000 ; board I/O base address |
.set BIO_WR,BIO_BASE+0 |
.set SPI_EN,0x80000000 ; SPI bus enable ctrl bit |
.set BIO_RD,BIO_BASE+4 |
.set CIO_CTRL,0x08 ; this bit controls console I/O |
|
.set CIO_KBD_DSP,0x00 ; set console to keyboard/display |
.set CIO_SERIAL_0,0x03 ; set console to serial line 0 |
|
.set dmapaddr,0xC0000000 ; base of directly mapped addresses |
.set stacktop,0xC0010000 ; monitor stack is at top of 64K |
|
.set PSW,0 ; reg # of PSW |
.set V_SHIFT,27 ; interrupt vector ctrl bit |
.set V,1 << V_SHIFT |
|
.set TLB_INDEX,1 ; reg # of TLB Index |
.set TLB_ENTRY_HI,2 ; reg # of TLB EntryHi |
.set TLB_ENTRY_LO,3 ; reg # of TLB EntryLo |
.set TLB_ENTRIES,32 ; number of TLB entries |
.set BAD_ADDRESS,4 ; reg # of bad address reg |
.set BAD_ACCESS,5 ; reg # of bad access reg |
|
.set USER_CONTEXT_SIZE,38*4 ; size of user context |
|
;*************************************************************** |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.import kbdinit |
.import kbdinchk |
.import kbdin |
|
.import dspinit |
.import dspoutchk |
.import dspout |
|
.import ser0init |
.import ser0inchk |
.import ser0in |
.import ser0outchk |
.import ser0out |
|
.import ser1init |
.import ser1inchk |
.import ser1in |
.import ser1outchk |
.import ser1out |
|
.import dskinitctl |
.import dskcapctl |
.import dskioctl |
|
.import dskinitser |
.import dskcapser |
.import dskioser |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export setcon |
.export cinchk |
.export cin |
.export coutchk |
.export cout |
.export dskcap |
.export dskio |
|
.export getTLB_HI |
.export getTLB_LO |
.export setTLB |
|
.export saveState |
.export monitorReturn |
|
.import userContext |
.export resume |
|
;*************************************************************** |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
;*************************************************************** |
|
.code |
.align 4 |
|
startup: |
j start |
|
interrupt: |
j debug |
|
userMiss: |
j debug |
|
monitor: |
j debug |
|
;*************************************************************** |
|
.code |
.align 4 |
|
setcon: |
j setcio |
|
cinchk: |
j cichk |
|
cin: |
j ci |
|
coutchk: |
j cochk |
|
cout: |
j co |
|
dskcap: |
j dcap |
|
dskio: |
j dio |
|
reserved_11: |
j reserved_11 |
|
reserved_12: |
j reserved_12 |
|
reserved_13: |
j reserved_13 |
|
reserved_14: |
j reserved_14 |
|
reserved_15: |
j reserved_15 |
|
;*************************************************************** |
|
.code |
.align 4 |
|
start: |
; let irq/exc vectors point to RAM |
add $8,$0,V |
mvts $8,PSW |
|
; disable flash ROM, enable SPI bus |
add $8,$0,BIO_WR |
add $9,$0,SPI_EN |
stw $9,$8,0 |
|
; initialize TLB |
mvts $0,TLB_ENTRY_LO ; invalidate all TLB entries |
add $8,$0,dmapaddr ; by impossible virtual page number |
mvts $8,TLB_ENTRY_HI |
add $8,$0,$0 |
add $9,$0,TLB_ENTRIES |
tlbloop: |
mvts $8,TLB_INDEX |
tbwi |
add $8,$8,1 |
bne $8,$9,tlbloop |
|
; copy data segment |
add $10,$0,_bdata ; lowest dst addr to be written to |
add $8,$0,_edata ; one above the top dst addr |
sub $9,$8,$10 ; $9 = size of data segment |
add $9,$9,_ecode ; data is waiting right after code |
j cpytest |
cpyloop: |
ldw $11,$9,0 ; src addr in $9 |
stw $11,$8,0 ; dst addr in $8 |
cpytest: |
sub $8,$8,4 ; downward |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
|
; clear bss segment |
add $8,$0,_bbss ; start with first word of bss |
add $9,$0,_ebss ; this is one above the top |
j clrtest |
clrloop: |
stw $0,$8,0 ; dst addr in $8 |
add $8,$8,4 ; upward |
clrtest: |
bltu $8,$9,clrloop |
|
; initialize I/O |
add $29,$0,stacktop ; setup monitor stack |
jal kbdinit ; init keyboard |
jal dspinit ; init display |
jal ser0init ; init serial line 0 |
jal ser1init ; init serial line 1 |
jal dskinitctl ; init disk (controller) |
jal dskinitser ; init disk (serial line) |
ldw $8,$0,BIO_RD ; get switch settings |
and $8,$8,CIO_CTRL |
add $4,$0,CIO_SERIAL_0 ; set console to serial line |
bne $8,$0,swtchset |
add $4,$0,CIO_KBD_DSP ; set console to kbd/dsp |
swtchset: |
jal setcio |
|
; call main |
jal main ; enter command loop |
|
; main should never return |
j start ; just to be sure... |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; Word getTLB_HI(int index) |
getTLB_HI: |
mvts $4,TLB_INDEX |
tbri |
mvfs $2,TLB_ENTRY_HI |
jr $31 |
|
; Word getTLB_LO(int index) |
getTLB_LO: |
mvts $4,TLB_INDEX |
tbri |
mvfs $2,TLB_ENTRY_LO |
jr $31 |
|
; void setTLB(int index, Word entryHi, Word entryLo) |
setTLB: |
mvts $4,TLB_INDEX |
mvts $5,TLB_ENTRY_HI |
mvts $6,TLB_ENTRY_LO |
tbwi |
jr $31 |
|
;*************************************************************** |
|
.data |
.align 4 |
|
cioctl: |
.byte 0 |
|
.code |
.align 4 |
|
; void setcon(Byte ctl) |
setcio: |
stb $4,$0,cioctl |
j $31 |
|
; int cinchk(void) |
cichk: |
ldbu $8,$0,cioctl |
and $8,$8,0x01 |
bne $8,$0,cichk1 |
j kbdinchk |
cichk1: |
j ser0inchk |
|
; char cin(void) |
ci: |
ldbu $8,$0,cioctl |
and $8,$8,0x01 |
bne $8,$0,ci1 |
j kbdin |
ci1: |
j ser0in |
|
; int coutchk(void) |
cochk: |
ldbu $8,$0,cioctl |
and $8,$8,0x02 |
bne $8,$0,cochk1 |
j dspoutchk |
cochk1: |
j ser0outchk |
|
; void cout(char c) |
co: |
ldbu $8,$0,cioctl |
and $8,$8,0x02 |
bne $8,$0,co1 |
j dspout |
co1: |
j ser0out |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; int dskcap(int dskno) |
dcap: |
bne $4,$0,dcapser |
j dskcapctl |
dcapser: |
j dskcapser |
|
; int dskio(int dskno, char cmd, int sct, Word addr, int nscts) |
dio: |
bne $4,$0,dioser |
add $4,$5,$0 |
add $5,$6,$0 |
add $6,$7,$0 |
ldw $7,$29,16 |
j dskioctl |
dioser: |
add $4,$5,$0 |
add $5,$6,$0 |
add $6,$7,$0 |
ldw $7,$29,16 |
j dskioser |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; Bool saveState(MonitorState *msp) |
; always return 'true' here |
saveState: |
stw $31,$4,0*4 ; return address |
stw $29,$4,1*4 ; stack pointer |
stw $16,$4,2*4 ; local variables |
stw $17,$4,3*4 |
stw $18,$4,4*4 |
stw $19,$4,5*4 |
stw $20,$4,6*4 |
stw $21,$4,7*4 |
stw $22,$4,8*4 |
stw $23,$4,9*4 |
add $2,$0,1 |
jr $31 |
|
; load state when re-entering monitor |
; this appears as if returning from saveState |
; but the return value is 'false' here |
loadState: |
ldw $8,$0,monitorReturn |
beq $8,$0,loadState ; fatal error: monitor state lost |
ldw $31,$8,0*4 ; return address |
ldw $29,$8,1*4 ; stack pointer |
ldw $16,$8,2*4 ; local variables |
ldw $17,$8,3*4 |
ldw $18,$8,4*4 |
ldw $19,$8,5*4 |
ldw $20,$8,6*4 |
ldw $21,$8,7*4 |
ldw $22,$8,8*4 |
ldw $23,$8,9*4 |
add $2,$0,0 |
jr $31 |
|
.bss |
.align 4 |
|
; extern MonitorState *monitorReturn |
monitorReturn: |
.space 4 |
|
; extern UserContext userContext |
userContext: |
.space USER_CONTEXT_SIZE |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; void resume(void) |
; use userContext to load state |
resume: |
mvts $0,PSW |
add $24,$0,userContext |
.nosyn |
ldw $8,$24,33*4 ; tlbIndex |
mvts $8,TLB_INDEX |
ldw $8,$24,34*4 ; tlbEntryHi |
mvts $8,TLB_ENTRY_HI |
ldw $8,$24,35*4 ; tlbEntryLo |
mvts $8,TLB_ENTRY_LO |
ldw $8,$24,36*4 ; badAddress |
mvts $8,BAD_ADDRESS |
ldw $8,$24,37*4 ; badAccess |
mvts $8,BAD_ACCESS |
;ldw $0,$24,0*4 ; registers |
ldw $1,$24,1*4 |
ldw $2,$24,2*4 |
ldw $3,$24,3*4 |
ldw $4,$24,4*4 |
ldw $5,$24,5*4 |
ldw $6,$24,6*4 |
ldw $7,$24,7*4 |
ldw $8,$24,8*4 |
ldw $9,$24,9*4 |
ldw $10,$24,10*4 |
ldw $11,$24,11*4 |
ldw $12,$24,12*4 |
ldw $13,$24,13*4 |
ldw $14,$24,14*4 |
ldw $15,$24,15*4 |
ldw $16,$24,16*4 |
ldw $17,$24,17*4 |
ldw $18,$24,18*4 |
ldw $19,$24,19*4 |
ldw $20,$24,20*4 |
ldw $21,$24,21*4 |
ldw $22,$24,22*4 |
ldw $23,$24,23*4 |
;ldw $24,$24,24*4 |
ldw $25,$24,25*4 |
ldw $26,$24,26*4 |
ldw $27,$24,27*4 |
ldw $28,$24,28*4 |
ldw $29,$24,29*4 |
ldw $30,$24,30*4 |
ldw $31,$24,31*4 |
ldw $24,$24,32*4 ; psw |
mvts $24,PSW |
rfx |
.syn |
|
; debug entry |
; use userContext to store state |
debug: |
.nosyn |
ldhi $24,userContext |
or $24,$24,userContext |
stw $0,$24,0*4 ; registers |
stw $1,$24,1*4 |
stw $2,$24,2*4 |
stw $3,$24,3*4 |
stw $4,$24,4*4 |
stw $5,$24,5*4 |
stw $6,$24,6*4 |
stw $7,$24,7*4 |
stw $8,$24,8*4 |
stw $9,$24,9*4 |
stw $10,$24,10*4 |
stw $11,$24,11*4 |
stw $12,$24,12*4 |
stw $13,$24,13*4 |
stw $14,$24,14*4 |
stw $15,$24,15*4 |
stw $16,$24,16*4 |
stw $17,$24,17*4 |
stw $18,$24,18*4 |
stw $19,$24,19*4 |
stw $20,$24,20*4 |
stw $21,$24,21*4 |
stw $22,$24,22*4 |
stw $23,$24,23*4 |
stw $24,$24,24*4 |
stw $25,$24,25*4 |
stw $26,$24,26*4 |
stw $27,$24,27*4 |
stw $28,$24,28*4 |
stw $29,$24,29*4 |
stw $30,$24,30*4 |
stw $31,$24,31*4 |
mvfs $8,PSW |
stw $8,$24,32*4 ; psw |
mvfs $8,TLB_INDEX |
stw $8,$24,33*4 ; tlbIndex |
mvfs $8,TLB_ENTRY_HI |
stw $8,$24,34*4 ; tlbEntryHi |
mvfs $8,TLB_ENTRY_LO |
stw $8,$24,35*4 ; tlbEntryLo |
mvfs $8,BAD_ADDRESS |
stw $8,$24,36*4 ; badAddress |
mvfs $8,BAD_ACCESS |
stw $8,$24,37*4 ; badAccess |
.syn |
j loadState |
/boards/s3e-500/Makefile
0,0 → 1,50
# |
# Makefile for ECO32 ROM monitor |
# |
|
BUILD = ../../../../build |
|
SRC = start.s \ |
../../common/main.c \ |
../../common/command.c \ |
../../common/instr.c \ |
../../common/asm.c \ |
../../common/disasm.c \ |
../../common/load.c \ |
../../common/boot.c \ |
../../common/cpu.c \ |
../../common/mmu.c \ |
../../common/getline.c \ |
../../common/romlib.c \ |
../../common/keyboard.s \ |
../../kbdtbls/kbdtbls.s \ |
../../common/display.s \ |
../../common/serial.s \ |
../../common/dskctl.s \ |
../../common/dskser.s \ |
../../common/end.s |
|
.PHONY: all install clean |
|
all: monitor.bin monitor.mcs |
|
install: monitor.bin monitor.mcs |
mkdir -p $(BUILD)/monitor/s3e-500 |
cp monitor.bin $(BUILD)/monitor/s3e-500 |
cp monitor.mcs $(BUILD)/monitor/s3e-500 |
|
monitor.mcs: monitor.bin |
$(BUILD)/bin/bin2mcs 0x00000000 monitor.bin monitor.mcs |
|
monitor.bin: $(SRC) |
$(BUILD)/bin/lcc -A -Wo-rom -Wl-rc -Wl0xC0000000 \ |
-Wl-rd -Wl0xC000C000 \ |
-Wl-m -Wlmonitor.map \ |
-o prelim.bin $(SRC) |
cat ../../copy/copy.bin prelim.bin >monitor.bin |
rm prelim.bin |
|
clean: |
rm -f *~ |
rm -f prelim.bin monitor.map monitor.bin |
rm -f monitor.mcs |
/boards/simulator/start.s
0,0 → 1,480
; |
; start.s -- ECO32 ROM monitor startup and support routines |
; |
|
; .set CIO_CTL,0x00 ; set console to keyboard/display |
.set CIO_CTL,0x03 ; set console to serial line 0 |
|
.set dmapaddr,0xC0000000 ; base of directly mapped addresses |
.set stacktop,0xC0010000 ; monitor stack is at top of 64K |
|
.set PSW,0 ; reg # of PSW |
.set V_SHIFT,27 ; interrupt vector ctrl bit |
.set V,1 << V_SHIFT |
|
.set TLB_INDEX,1 ; reg # of TLB Index |
.set TLB_ENTRY_HI,2 ; reg # of TLB EntryHi |
.set TLB_ENTRY_LO,3 ; reg # of TLB EntryLo |
.set TLB_ENTRIES,32 ; number of TLB entries |
.set BAD_ADDRESS,4 ; reg # of bad address reg |
.set BAD_ACCESS,5 ; reg # of bad access reg |
|
.set USER_CONTEXT_SIZE,38*4 ; size of user context |
|
;*************************************************************** |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.import kbdinit |
.import kbdinchk |
.import kbdin |
|
.import dspinit |
.import dspoutchk |
.import dspout |
|
.import ser0init |
.import ser0inchk |
.import ser0in |
.import ser0outchk |
.import ser0out |
|
.import ser1init |
.import ser1inchk |
.import ser1in |
.import ser1outchk |
.import ser1out |
|
.import dskinitctl |
.import dskcapctl |
.import dskioctl |
|
.import dskinitser |
.import dskcapser |
.import dskioser |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export setcon |
.export cinchk |
.export cin |
.export coutchk |
.export cout |
.export dskcap |
.export dskio |
|
.export getTLB_HI |
.export getTLB_LO |
.export setTLB |
|
.export saveState |
.export monitorReturn |
|
.import userContext |
.export resume |
|
;*************************************************************** |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
;*************************************************************** |
|
.code |
.align 4 |
|
startup: |
j start |
|
interrupt: |
j debug |
|
userMiss: |
j debug |
|
monitor: |
j debug |
|
;*************************************************************** |
|
.code |
.align 4 |
|
setcon: |
j setcio |
|
cinchk: |
j cichk |
|
cin: |
j ci |
|
coutchk: |
j cochk |
|
cout: |
j co |
|
dskcap: |
j dcap |
|
dskio: |
j dio |
|
reserved_11: |
j reserved_11 |
|
reserved_12: |
j reserved_12 |
|
reserved_13: |
j reserved_13 |
|
reserved_14: |
j reserved_14 |
|
reserved_15: |
j reserved_15 |
|
;*************************************************************** |
|
.code |
.align 4 |
|
start: |
; let irq/exc vectors point to RAM |
add $8,$0,V |
mvts $8,PSW |
|
; initialize TLB |
mvts $0,TLB_ENTRY_LO ; invalidate all TLB entries |
add $8,$0,dmapaddr ; by impossible virtual page number |
mvts $8,TLB_ENTRY_HI |
add $8,$0,$0 |
add $9,$0,TLB_ENTRIES |
tlbloop: |
mvts $8,TLB_INDEX |
tbwi |
add $8,$8,1 |
bne $8,$9,tlbloop |
|
; copy data segment |
add $10,$0,_bdata ; lowest dst addr to be written to |
add $8,$0,_edata ; one above the top dst addr |
sub $9,$8,$10 ; $9 = size of data segment |
add $9,$9,_ecode ; data is waiting right after code |
j cpytest |
cpyloop: |
ldw $11,$9,0 ; src addr in $9 |
stw $11,$8,0 ; dst addr in $8 |
cpytest: |
sub $8,$8,4 ; downward |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
|
; clear bss segment |
add $8,$0,_bbss ; start with first word of bss |
add $9,$0,_ebss ; this is one above the top |
j clrtest |
clrloop: |
stw $0,$8,0 ; dst addr in $8 |
add $8,$8,4 ; upward |
clrtest: |
bltu $8,$9,clrloop |
|
; initialize I/O |
add $29,$0,stacktop ; setup monitor stack |
jal kbdinit ; init keyboard |
jal dspinit ; init display |
jal ser0init ; init serial line 0 |
jal ser1init ; init serial line 1 |
jal dskinitctl ; init disk (controller) |
jal dskinitser ; init disk (serial line) |
add $4,$0,CIO_CTL ; set console |
jal setcio |
|
; call main |
jal main ; enter command loop |
|
; main should never return |
j start ; just to be sure... |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; Word getTLB_HI(int index) |
getTLB_HI: |
mvts $4,TLB_INDEX |
tbri |
mvfs $2,TLB_ENTRY_HI |
jr $31 |
|
; Word getTLB_LO(int index) |
getTLB_LO: |
mvts $4,TLB_INDEX |
tbri |
mvfs $2,TLB_ENTRY_LO |
jr $31 |
|
; void setTLB(int index, Word entryHi, Word entryLo) |
setTLB: |
mvts $4,TLB_INDEX |
mvts $5,TLB_ENTRY_HI |
mvts $6,TLB_ENTRY_LO |
tbwi |
jr $31 |
|
;*************************************************************** |
|
.data |
.align 4 |
|
cioctl: |
.byte 0 |
|
.code |
.align 4 |
|
; void setcon(Byte ctl) |
setcio: |
stb $4,$0,cioctl |
j $31 |
|
; int cinchk(void) |
cichk: |
ldbu $8,$0,cioctl |
and $8,$8,0x01 |
bne $8,$0,cichk1 |
j kbdinchk |
cichk1: |
j ser0inchk |
|
; char cin(void) |
ci: |
ldbu $8,$0,cioctl |
and $8,$8,0x01 |
bne $8,$0,ci1 |
j kbdin |
ci1: |
j ser0in |
|
; int coutchk(void) |
cochk: |
ldbu $8,$0,cioctl |
and $8,$8,0x02 |
bne $8,$0,cochk1 |
j dspoutchk |
cochk1: |
j ser0outchk |
|
; void cout(char c) |
co: |
ldbu $8,$0,cioctl |
and $8,$8,0x02 |
bne $8,$0,co1 |
j dspout |
co1: |
j ser0out |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; int dskcap(int dskno) |
dcap: |
bne $4,$0,dcapser |
j dskcapctl |
dcapser: |
j dskcapser |
|
; int dskio(int dskno, char cmd, int sct, Word addr, int nscts) |
dio: |
bne $4,$0,dioser |
add $4,$5,$0 |
add $5,$6,$0 |
add $6,$7,$0 |
ldw $7,$29,16 |
j dskioctl |
dioser: |
add $4,$5,$0 |
add $5,$6,$0 |
add $6,$7,$0 |
ldw $7,$29,16 |
j dskioser |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; Bool saveState(MonitorState *msp) |
; always return 'true' here |
saveState: |
stw $31,$4,0*4 ; return address |
stw $29,$4,1*4 ; stack pointer |
stw $16,$4,2*4 ; local variables |
stw $17,$4,3*4 |
stw $18,$4,4*4 |
stw $19,$4,5*4 |
stw $20,$4,6*4 |
stw $21,$4,7*4 |
stw $22,$4,8*4 |
stw $23,$4,9*4 |
add $2,$0,1 |
jr $31 |
|
; load state when re-entering monitor |
; this appears as if returning from saveState |
; but the return value is 'false' here |
loadState: |
ldw $8,$0,monitorReturn |
beq $8,$0,loadState ; fatal error: monitor state lost |
ldw $31,$8,0*4 ; return address |
ldw $29,$8,1*4 ; stack pointer |
ldw $16,$8,2*4 ; local variables |
ldw $17,$8,3*4 |
ldw $18,$8,4*4 |
ldw $19,$8,5*4 |
ldw $20,$8,6*4 |
ldw $21,$8,7*4 |
ldw $22,$8,8*4 |
ldw $23,$8,9*4 |
add $2,$0,0 |
jr $31 |
|
.bss |
.align 4 |
|
; extern MonitorState *monitorReturn |
monitorReturn: |
.space 4 |
|
; extern UserContext userContext |
userContext: |
.space USER_CONTEXT_SIZE |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; void resume(void) |
; use userContext to load state |
resume: |
mvts $0,PSW |
add $24,$0,userContext |
.nosyn |
ldw $8,$24,33*4 ; tlbIndex |
mvts $8,TLB_INDEX |
ldw $8,$24,34*4 ; tlbEntryHi |
mvts $8,TLB_ENTRY_HI |
ldw $8,$24,35*4 ; tlbEntryLo |
mvts $8,TLB_ENTRY_LO |
ldw $8,$24,36*4 ; badAddress |
mvts $8,BAD_ADDRESS |
ldw $8,$24,37*4 ; badAccess |
mvts $8,BAD_ACCESS |
;ldw $0,$24,0*4 ; registers |
ldw $1,$24,1*4 |
ldw $2,$24,2*4 |
ldw $3,$24,3*4 |
ldw $4,$24,4*4 |
ldw $5,$24,5*4 |
ldw $6,$24,6*4 |
ldw $7,$24,7*4 |
ldw $8,$24,8*4 |
ldw $9,$24,9*4 |
ldw $10,$24,10*4 |
ldw $11,$24,11*4 |
ldw $12,$24,12*4 |
ldw $13,$24,13*4 |
ldw $14,$24,14*4 |
ldw $15,$24,15*4 |
ldw $16,$24,16*4 |
ldw $17,$24,17*4 |
ldw $18,$24,18*4 |
ldw $19,$24,19*4 |
ldw $20,$24,20*4 |
ldw $21,$24,21*4 |
ldw $22,$24,22*4 |
ldw $23,$24,23*4 |
;ldw $24,$24,24*4 |
ldw $25,$24,25*4 |
ldw $26,$24,26*4 |
ldw $27,$24,27*4 |
ldw $28,$24,28*4 |
ldw $29,$24,29*4 |
ldw $30,$24,30*4 |
ldw $31,$24,31*4 |
ldw $24,$24,32*4 ; psw |
mvts $24,PSW |
rfx |
.syn |
|
; debug entry |
; use userContext to store state |
debug: |
.nosyn |
ldhi $24,userContext |
or $24,$24,userContext |
stw $0,$24,0*4 ; registers |
stw $1,$24,1*4 |
stw $2,$24,2*4 |
stw $3,$24,3*4 |
stw $4,$24,4*4 |
stw $5,$24,5*4 |
stw $6,$24,6*4 |
stw $7,$24,7*4 |
stw $8,$24,8*4 |
stw $9,$24,9*4 |
stw $10,$24,10*4 |
stw $11,$24,11*4 |
stw $12,$24,12*4 |
stw $13,$24,13*4 |
stw $14,$24,14*4 |
stw $15,$24,15*4 |
stw $16,$24,16*4 |
stw $17,$24,17*4 |
stw $18,$24,18*4 |
stw $19,$24,19*4 |
stw $20,$24,20*4 |
stw $21,$24,21*4 |
stw $22,$24,22*4 |
stw $23,$24,23*4 |
stw $24,$24,24*4 |
stw $25,$24,25*4 |
stw $26,$24,26*4 |
stw $27,$24,27*4 |
stw $28,$24,28*4 |
stw $29,$24,29*4 |
stw $30,$24,30*4 |
stw $31,$24,31*4 |
mvfs $8,PSW |
stw $8,$24,32*4 ; psw |
mvfs $8,TLB_INDEX |
stw $8,$24,33*4 ; tlbIndex |
mvfs $8,TLB_ENTRY_HI |
stw $8,$24,34*4 ; tlbEntryHi |
mvfs $8,TLB_ENTRY_LO |
stw $8,$24,35*4 ; tlbEntryLo |
mvfs $8,BAD_ADDRESS |
stw $8,$24,36*4 ; badAddress |
mvfs $8,BAD_ACCESS |
stw $8,$24,37*4 ; badAccess |
.syn |
j loadState |
/boards/simulator/Makefile
0,0 → 1,45
# |
# Makefile for ECO32 ROM monitor |
# |
|
BUILD = ../../../../build |
|
SRC = start.s \ |
../../common/main.c \ |
../../common/command.c \ |
../../common/instr.c \ |
../../common/asm.c \ |
../../common/disasm.c \ |
../../common/load.c \ |
../../common/boot.c \ |
../../common/cpu.c \ |
../../common/mmu.c \ |
../../common/getline.c \ |
../../common/romlib.c \ |
../../common/keyboard.s \ |
../../kbdtbls/kbdtbls.s \ |
../../common/display.s \ |
../../common/serial.s \ |
../../common/dskctl.s \ |
../../common/dskser.s \ |
../../common/end.s |
|
.PHONY: all install clean |
|
all: monitor.bin |
|
install: monitor.bin |
mkdir -p $(BUILD)/monitor/simulator |
cp monitor.bin $(BUILD)/monitor/simulator |
|
monitor.bin: $(SRC) |
$(BUILD)/bin/lcc -A -Wo-rom -Wl-rc -Wl0xC0000000 \ |
-Wl-rd -Wl0xC000C000 \ |
-Wl-m -Wlmonitor.map \ |
-o prelim.bin $(SRC) |
cat ../../copy/copy.bin prelim.bin >monitor.bin |
rm prelim.bin |
|
clean: |
rm -f *~ |
rm -f prelim.bin monitor.map monitor.bin |
/boards/xsa-xst-3/start.s
0,0 → 1,490
; |
; start.s -- ECO32 ROM monitor startup and support routines |
; |
|
.set BIO_BASE,0xF1000000 ; board I/O base address |
.set BIO_WR,BIO_BASE+0 |
.set BIO_RD,BIO_BASE+4 |
.set CIO_CTRL,0x08 ; this bit controls console I/O |
|
.set CIO_KBD_DSP,0x00 ; set console to keyboard/display |
.set CIO_SERIAL_0,0x03 ; set console to serial line 0 |
|
.set dmapaddr,0xC0000000 ; base of directly mapped addresses |
.set stacktop,0xC0010000 ; monitor stack is at top of 64K |
|
.set PSW,0 ; reg # of PSW |
.set V_SHIFT,27 ; interrupt vector ctrl bit |
.set V,1 << V_SHIFT |
|
.set TLB_INDEX,1 ; reg # of TLB Index |
.set TLB_ENTRY_HI,2 ; reg # of TLB EntryHi |
.set TLB_ENTRY_LO,3 ; reg # of TLB EntryLo |
.set TLB_ENTRIES,32 ; number of TLB entries |
.set BAD_ADDRESS,4 ; reg # of bad address reg |
.set BAD_ACCESS,5 ; reg # of bad access reg |
|
.set USER_CONTEXT_SIZE,38*4 ; size of user context |
|
;*************************************************************** |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.import kbdinit |
.import kbdinchk |
.import kbdin |
|
.import dspinit |
.import dspoutchk |
.import dspout |
|
.import ser0init |
.import ser0inchk |
.import ser0in |
.import ser0outchk |
.import ser0out |
|
.import ser1init |
.import ser1inchk |
.import ser1in |
.import ser1outchk |
.import ser1out |
|
.import dskinitctl |
.import dskcapctl |
.import dskioctl |
|
.import dskinitser |
.import dskcapser |
.import dskioser |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export setcon |
.export cinchk |
.export cin |
.export coutchk |
.export cout |
.export dskcap |
.export dskio |
|
.export getTLB_HI |
.export getTLB_LO |
.export setTLB |
|
.export saveState |
.export monitorReturn |
|
.import userContext |
.export resume |
|
;*************************************************************** |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
;*************************************************************** |
|
.code |
.align 4 |
|
startup: |
j start |
|
interrupt: |
j debug |
|
userMiss: |
j debug |
|
monitor: |
j debug |
|
;*************************************************************** |
|
.code |
.align 4 |
|
setcon: |
j setcio |
|
cinchk: |
j cichk |
|
cin: |
j ci |
|
coutchk: |
j cochk |
|
cout: |
j co |
|
dskcap: |
j dcap |
|
dskio: |
j dio |
|
reserved_11: |
j reserved_11 |
|
reserved_12: |
j reserved_12 |
|
reserved_13: |
j reserved_13 |
|
reserved_14: |
j reserved_14 |
|
reserved_15: |
j reserved_15 |
|
;*************************************************************** |
|
.code |
.align 4 |
|
start: |
; let irq/exc vectors point to RAM |
add $8,$0,V |
mvts $8,PSW |
|
; initialize TLB |
mvts $0,TLB_ENTRY_LO ; invalidate all TLB entries |
add $8,$0,dmapaddr ; by impossible virtual page number |
mvts $8,TLB_ENTRY_HI |
add $8,$0,$0 |
add $9,$0,TLB_ENTRIES |
tlbloop: |
mvts $8,TLB_INDEX |
tbwi |
add $8,$8,1 |
bne $8,$9,tlbloop |
|
; copy data segment |
add $10,$0,_bdata ; lowest dst addr to be written to |
add $8,$0,_edata ; one above the top dst addr |
sub $9,$8,$10 ; $9 = size of data segment |
add $9,$9,_ecode ; data is waiting right after code |
j cpytest |
cpyloop: |
ldw $11,$9,0 ; src addr in $9 |
stw $11,$8,0 ; dst addr in $8 |
cpytest: |
sub $8,$8,4 ; downward |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
|
; clear bss segment |
add $8,$0,_bbss ; start with first word of bss |
add $9,$0,_ebss ; this is one above the top |
j clrtest |
clrloop: |
stw $0,$8,0 ; dst addr in $8 |
add $8,$8,4 ; upward |
clrtest: |
bltu $8,$9,clrloop |
|
; initialize I/O |
add $29,$0,stacktop ; setup monitor stack |
jal kbdinit ; init keyboard |
jal dspinit ; init display |
jal ser0init ; init serial line 0 |
jal ser1init ; init serial line 1 |
jal dskinitctl ; init disk (controller) |
jal dskinitser ; init disk (serial line) |
ldw $8,$0,BIO_RD ; get switch settings |
and $8,$8,CIO_CTRL |
add $4,$0,CIO_SERIAL_0 ; set console to serial line |
bne $8,$0,swtchset |
add $4,$0,CIO_KBD_DSP ; set console to kbd/dsp |
swtchset: |
jal setcio |
|
; call main |
jal main ; enter command loop |
|
; main should never return |
j start ; just to be sure... |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; Word getTLB_HI(int index) |
getTLB_HI: |
mvts $4,TLB_INDEX |
tbri |
mvfs $2,TLB_ENTRY_HI |
jr $31 |
|
; Word getTLB_LO(int index) |
getTLB_LO: |
mvts $4,TLB_INDEX |
tbri |
mvfs $2,TLB_ENTRY_LO |
jr $31 |
|
; void setTLB(int index, Word entryHi, Word entryLo) |
setTLB: |
mvts $4,TLB_INDEX |
mvts $5,TLB_ENTRY_HI |
mvts $6,TLB_ENTRY_LO |
tbwi |
jr $31 |
|
;*************************************************************** |
|
.data |
.align 4 |
|
cioctl: |
.byte 0 |
|
.code |
.align 4 |
|
; void setcon(Byte ctl) |
setcio: |
stb $4,$0,cioctl |
j $31 |
|
; int cinchk(void) |
cichk: |
ldbu $8,$0,cioctl |
and $8,$8,0x01 |
bne $8,$0,cichk1 |
j kbdinchk |
cichk1: |
j ser0inchk |
|
; char cin(void) |
ci: |
ldbu $8,$0,cioctl |
and $8,$8,0x01 |
bne $8,$0,ci1 |
j kbdin |
ci1: |
j ser0in |
|
; int coutchk(void) |
cochk: |
ldbu $8,$0,cioctl |
and $8,$8,0x02 |
bne $8,$0,cochk1 |
j dspoutchk |
cochk1: |
j ser0outchk |
|
; void cout(char c) |
co: |
ldbu $8,$0,cioctl |
and $8,$8,0x02 |
bne $8,$0,co1 |
j dspout |
co1: |
j ser0out |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; int dskcap(int dskno) |
dcap: |
bne $4,$0,dcapser |
j dskcapctl |
dcapser: |
j dskcapser |
|
; int dskio(int dskno, char cmd, int sct, Word addr, int nscts) |
dio: |
bne $4,$0,dioser |
add $4,$5,$0 |
add $5,$6,$0 |
add $6,$7,$0 |
ldw $7,$29,16 |
j dskioctl |
dioser: |
add $4,$5,$0 |
add $5,$6,$0 |
add $6,$7,$0 |
ldw $7,$29,16 |
j dskioser |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; Bool saveState(MonitorState *msp) |
; always return 'true' here |
saveState: |
stw $31,$4,0*4 ; return address |
stw $29,$4,1*4 ; stack pointer |
stw $16,$4,2*4 ; local variables |
stw $17,$4,3*4 |
stw $18,$4,4*4 |
stw $19,$4,5*4 |
stw $20,$4,6*4 |
stw $21,$4,7*4 |
stw $22,$4,8*4 |
stw $23,$4,9*4 |
add $2,$0,1 |
jr $31 |
|
; load state when re-entering monitor |
; this appears as if returning from saveState |
; but the return value is 'false' here |
loadState: |
ldw $8,$0,monitorReturn |
beq $8,$0,loadState ; fatal error: monitor state lost |
ldw $31,$8,0*4 ; return address |
ldw $29,$8,1*4 ; stack pointer |
ldw $16,$8,2*4 ; local variables |
ldw $17,$8,3*4 |
ldw $18,$8,4*4 |
ldw $19,$8,5*4 |
ldw $20,$8,6*4 |
ldw $21,$8,7*4 |
ldw $22,$8,8*4 |
ldw $23,$8,9*4 |
add $2,$0,0 |
jr $31 |
|
.bss |
.align 4 |
|
; extern MonitorState *monitorReturn |
monitorReturn: |
.space 4 |
|
; extern UserContext userContext |
userContext: |
.space USER_CONTEXT_SIZE |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; void resume(void) |
; use userContext to load state |
resume: |
mvts $0,PSW |
add $24,$0,userContext |
.nosyn |
ldw $8,$24,33*4 ; tlbIndex |
mvts $8,TLB_INDEX |
ldw $8,$24,34*4 ; tlbEntryHi |
mvts $8,TLB_ENTRY_HI |
ldw $8,$24,35*4 ; tlbEntryLo |
mvts $8,TLB_ENTRY_LO |
ldw $8,$24,36*4 ; badAddress |
mvts $8,BAD_ADDRESS |
ldw $8,$24,37*4 ; badAccess |
mvts $8,BAD_ACCESS |
;ldw $0,$24,0*4 ; registers |
ldw $1,$24,1*4 |
ldw $2,$24,2*4 |
ldw $3,$24,3*4 |
ldw $4,$24,4*4 |
ldw $5,$24,5*4 |
ldw $6,$24,6*4 |
ldw $7,$24,7*4 |
ldw $8,$24,8*4 |
ldw $9,$24,9*4 |
ldw $10,$24,10*4 |
ldw $11,$24,11*4 |
ldw $12,$24,12*4 |
ldw $13,$24,13*4 |
ldw $14,$24,14*4 |
ldw $15,$24,15*4 |
ldw $16,$24,16*4 |
ldw $17,$24,17*4 |
ldw $18,$24,18*4 |
ldw $19,$24,19*4 |
ldw $20,$24,20*4 |
ldw $21,$24,21*4 |
ldw $22,$24,22*4 |
ldw $23,$24,23*4 |
;ldw $24,$24,24*4 |
ldw $25,$24,25*4 |
ldw $26,$24,26*4 |
ldw $27,$24,27*4 |
ldw $28,$24,28*4 |
ldw $29,$24,29*4 |
ldw $30,$24,30*4 |
ldw $31,$24,31*4 |
ldw $24,$24,32*4 ; psw |
mvts $24,PSW |
rfx |
.syn |
|
; debug entry |
; use userContext to store state |
debug: |
.nosyn |
ldhi $24,userContext |
or $24,$24,userContext |
stw $0,$24,0*4 ; registers |
stw $1,$24,1*4 |
stw $2,$24,2*4 |
stw $3,$24,3*4 |
stw $4,$24,4*4 |
stw $5,$24,5*4 |
stw $6,$24,6*4 |
stw $7,$24,7*4 |
stw $8,$24,8*4 |
stw $9,$24,9*4 |
stw $10,$24,10*4 |
stw $11,$24,11*4 |
stw $12,$24,12*4 |
stw $13,$24,13*4 |
stw $14,$24,14*4 |
stw $15,$24,15*4 |
stw $16,$24,16*4 |
stw $17,$24,17*4 |
stw $18,$24,18*4 |
stw $19,$24,19*4 |
stw $20,$24,20*4 |
stw $21,$24,21*4 |
stw $22,$24,22*4 |
stw $23,$24,23*4 |
stw $24,$24,24*4 |
stw $25,$24,25*4 |
stw $26,$24,26*4 |
stw $27,$24,27*4 |
stw $28,$24,28*4 |
stw $29,$24,29*4 |
stw $30,$24,30*4 |
stw $31,$24,31*4 |
mvfs $8,PSW |
stw $8,$24,32*4 ; psw |
mvfs $8,TLB_INDEX |
stw $8,$24,33*4 ; tlbIndex |
mvfs $8,TLB_ENTRY_HI |
stw $8,$24,34*4 ; tlbEntryHi |
mvfs $8,TLB_ENTRY_LO |
stw $8,$24,35*4 ; tlbEntryLo |
mvfs $8,BAD_ADDRESS |
stw $8,$24,36*4 ; badAddress |
mvfs $8,BAD_ACCESS |
stw $8,$24,37*4 ; badAccess |
.syn |
j loadState |
/boards/xsa-xst-3/Makefile
0,0 → 1,50
# |
# Makefile for ECO32 ROM monitor |
# |
|
BUILD = ../../../../build |
|
SRC = start.s \ |
../../common/main.c \ |
../../common/command.c \ |
../../common/instr.c \ |
../../common/asm.c \ |
../../common/disasm.c \ |
../../common/load.c \ |
../../common/boot.c \ |
../../common/cpu.c \ |
../../common/mmu.c \ |
../../common/getline.c \ |
../../common/romlib.c \ |
../../common/keyboard.s \ |
../../kbdtbls/kbdtbls.s \ |
../../common/display.s \ |
../../common/serial.s \ |
../../common/dskctl.s \ |
../../common/dskser.s \ |
../../common/end.s |
|
.PHONY: all install clean |
|
all: monitor.bin monitor.exo |
|
install: monitor.bin monitor.exo |
mkdir -p $(BUILD)/monitor/xsa-xst-3 |
cp monitor.bin $(BUILD)/monitor/xsa-xst-3 |
cp monitor.exo $(BUILD)/monitor/xsa-xst-3 |
|
monitor.exo: monitor.bin |
$(BUILD)/bin/bin2exo -S2 0 monitor.bin monitor.exo |
|
monitor.bin: $(SRC) |
$(BUILD)/bin/lcc -A -Wo-rom -Wl-rc -Wl0xC0000000 \ |
-Wl-rd -Wl0xC000C000 \ |
-Wl-m -Wlmonitor.map \ |
-o prelim.bin $(SRC) |
cat ../../copy/copy.bin prelim.bin >monitor.bin |
rm prelim.bin |
|
clean: |
rm -f *~ |
rm -f prelim.bin monitor.map monitor.bin |
rm -f monitor.exo |
/boards/Makefile
0,0 → 1,25
# |
# Makefile for building the ECO32 ROM monitor for different boards |
# |
|
BUILD = ../../../build |
|
DIRS = simulator xsa-xst-3 s3e-500 |
|
.PHONY: all install clean |
|
all: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i all ; \ |
done |
|
install: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i install ; \ |
done |
|
clean: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i clean ; \ |
done |
rm -f *~ |
/common/command.c
0,0 → 1,917
/* |
* command.c -- command interpreter |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "getline.h" |
#include "command.h" |
#include "asm.h" |
#include "disasm.h" |
#include "load.h" |
#include "boot.h" |
#include "cpu.h" |
#include "mmu.h" |
#include "start.h" |
|
|
#define MAX_TOKENS 10 |
|
|
typedef struct { |
char *name; |
void (*hlpProc)(void); |
void (*cmdProc)(char *tokens[], int n); |
} Command; |
|
extern Command commands[]; |
extern int numCommands; |
|
|
static void help(void) { |
printf("valid commands are:\n"); |
printf(" help get help\n"); |
printf(" + add and subtract\n"); |
printf(" a assemble\n"); |
printf(" u unassemble\n"); |
printf(" b set/reset breakpoint\n"); |
printf(" c continue from breakpoint\n"); |
printf(" s single-step\n"); |
printf(" # show/set PC\n"); |
printf(" p show/set PSW\n"); |
printf(" r show/set register\n"); |
printf(" d dump memory\n"); |
printf(" mw show/set memory word\n"); |
printf(" mh show/set memory halfword\n"); |
printf(" mb show/set memory byte\n"); |
printf(" t show/set TLB contents\n"); |
printf(" load load from serial line\n"); |
printf(" boot bootstrap from disk\n"); |
printf("type 'help <cmd>' to get help for <cmd>\n"); |
} |
|
|
static void help00(void) { |
printf(" help show a list of commands\n"); |
printf(" help <cmd> show help for <cmd>\n"); |
} |
|
|
static void help01(void) { |
printf(" + <num1> <num2> add and subtract <num1> and <num2>\n"); |
} |
|
|
static void help02(void) { |
printf(" a assemble starting at PC\n"); |
printf(" a <addr> assemble starting at <addr>\n"); |
} |
|
|
static void help03(void) { |
printf(" u unassemble 16 instrs starting at PC\n"); |
printf(" u <addr> unassemble 16 instrs starting at <addr>\n"); |
printf(" u <addr> <cnt> unassemble <cnt> instrs starting at <addr>\n"); |
} |
|
|
static void help04(void) { |
printf(" b reset break\n"); |
printf(" b <addr> set break at <addr>\n"); |
} |
|
|
static void help05(void) { |
printf(" c continue execution\n"); |
printf(" c <cnt> continue execution <cnt> times\n"); |
} |
|
|
static void help06(void) { |
printf(" s single-step one instruction\n"); |
printf(" s <cnt> single-step <cnt> instructions\n"); |
} |
|
|
static void help07(void) { |
printf(" # show PC\n"); |
printf(" # <addr> set PC to <addr>\n"); |
} |
|
|
static void help08(void) { |
printf(" p show PSW\n"); |
printf(" p <data> set PSW to <data>\n"); |
} |
|
|
static void help09(void) { |
printf(" r show all registers\n"); |
printf(" r <reg> show register <reg>\n"); |
printf(" r <reg> <data> set register <reg> to <data>\n"); |
} |
|
|
static void help10(void) { |
printf(" d dump 256 bytes starting at PC\n"); |
printf(" d <addr> dump 256 bytes starting at <addr>\n"); |
printf(" d <addr> <cnt> dump <cnt> bytes starting at <addr>\n"); |
} |
|
|
static void help11(void) { |
printf(" mw show memory word at PC\n"); |
printf(" mw <addr> show memory word at <addr>\n"); |
printf(" mw <addr> <data> set memory word at <addr> to <data>\n"); |
} |
|
|
static void help12(void) { |
printf(" mh show memory halfword at PC\n"); |
printf(" mh <addr> show memory halfword at <addr>\n"); |
printf(" mh <addr> <data> set memory halfword at <addr> to <data>\n"); |
} |
|
|
static void help13(void) { |
printf(" mb show memory byte at PC\n"); |
printf(" mb <addr> show memory byte at <addr>\n"); |
printf(" mb <addr> <data> set memory byte at <addr> to <data>\n"); |
} |
|
|
static void help14(void) { |
printf(" t show TLB contents\n"); |
printf(" t <i> show TLB contents at <i>\n"); |
printf(" t <i> p <data> set TLB contents at <i> to page <data>\n"); |
printf(" t <i> f <data> set TLB contents at <i> to frame <data>\n"); |
} |
|
|
static void help15(void) { |
printf(" load <n> load/start S-records from serial line <n>\n"); |
printf(" load <n> * load S-records from serial line <n>\n"); |
} |
|
|
static void help16(void) { |
printf(" boot <n> load/start first sector of disk <n>\n"); |
printf(" boot <n> * load first sector of disk <n>\n"); |
} |
|
|
static Bool getHexNumber(char *str, Word *valptr) { |
char *end; |
|
*valptr = strtoul(str, &end, 16); |
return *end == '\0'; |
} |
|
|
static Bool getDecNumber(char *str, int *valptr) { |
char *end; |
|
*valptr = strtoul(str, &end, 10); |
return *end == '\0'; |
} |
|
|
static void showPC(void) { |
Word pc, psw; |
Word instr; |
|
pc = cpuGetPC(); |
psw = cpuGetPSW(); |
instr = mmuReadWord(pc); |
printf("PC %08X [PC] %08X %s\n", |
pc, instr, disasm(instr, pc)); |
} |
|
|
static void showBreak(void) { |
Word brk; |
|
brk = cpuGetBreak(); |
printf("brk "); |
if (cpuTestBreak()) { |
printf("%08X", brk); |
} else { |
printf("--------"); |
} |
printf("\n"); |
} |
|
|
static void showPSW(void) { |
Word psw; |
int i; |
|
psw = cpuGetPSW(); |
printf(" xxxx V UPO IPO IACK MASK\n"); |
printf("PSW "); |
for (i = 31; i >= 0; i--) { |
if (i == 27 || i == 26 || i == 23 || i == 20 || i == 15) { |
printf(" "); |
} |
printf("%c", psw & (1 << i) ? '1' : '0'); |
} |
printf("\n"); |
} |
|
|
static void doHelp(char *tokens[], int n) { |
int i; |
|
if (n == 1) { |
help(); |
} else if (n == 2) { |
for (i = 0; i < numCommands; i++) { |
if (strcmp(commands[i].name, tokens[1]) == 0) { |
(*commands[i].hlpProc)(); |
return; |
} |
} |
printf("no help available for '%s', sorry\n", tokens[1]); |
} else { |
help00(); |
} |
} |
|
|
static void doArith(char *tokens[], int n) { |
Word num1, num2, num3, num4; |
|
if (n == 3) { |
if (!getHexNumber(tokens[1], &num1)) { |
printf("illegal first number\n"); |
return; |
} |
if (!getHexNumber(tokens[2], &num2)) { |
printf("illegal second number\n"); |
return; |
} |
num3 = num1 + num2; |
num4 = num1 - num2; |
printf("add = %08X, sub = %08X\n", num3, num4); |
} else { |
help01(); |
} |
} |
|
|
static void doAssemble(char *tokens[], int n) { |
Word addr; |
Word psw; |
char prompt[30]; |
char *line; |
char *msg; |
Word instr; |
|
if (n == 1) { |
addr = cpuGetPC(); |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
} else { |
help02(); |
return; |
} |
addr &= ~0x00000003; |
psw = cpuGetPSW(); |
while (1) { |
sprintf(prompt, "ASM # %08X: ", addr); |
line = getLine(prompt); |
if (*line == '\0' || *line == '\n') { |
break; |
} |
addHist(line); |
msg = asmInstr(line, addr, &instr); |
if (msg != NULL) { |
printf("%s\n", msg); |
} else { |
mmuWriteWord(addr, instr); |
addr += 4; |
} |
} |
} |
|
|
static void doUnassemble(char *tokens[], int n) { |
Word addr, count; |
Word psw; |
int i; |
Word instr; |
|
if (n == 1) { |
addr = cpuGetPC(); |
count = 16; |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
count = 16; |
} else if (n == 3) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
if (!getHexNumber(tokens[2], &count)) { |
printf("illegal count\n"); |
return; |
} |
if (count == 0) { |
return; |
} |
} else { |
help03(); |
return; |
} |
addr &= ~0x00000003; |
psw = cpuGetPSW(); |
for (i = 0; i < count; i++) { |
instr = mmuReadWord(addr); |
printf("%08X: %08X %s\n", |
addr, instr, disasm(instr, addr)); |
if (addr + 4 < addr) { |
/* wrap-around */ |
break; |
} |
addr += 4; |
} |
} |
|
|
static void doBreak(char *tokens[], int n) { |
Word addr; |
|
if (n == 1) { |
cpuResetBreak(); |
showBreak(); |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
addr &= ~0x00000003; |
cpuSetBreak(addr); |
showBreak(); |
} else { |
help04(); |
} |
} |
|
|
static void doContinue(char *tokens[], int n) { |
Word count, i; |
Word addr; |
|
if (n == 1) { |
count = 1; |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &count) || count == 0) { |
printf("illegal count\n"); |
return; |
} |
} else { |
help05(); |
return; |
} |
for (i = 0; i < count; i++) { |
cpuRun(); |
} |
addr = cpuGetPC(); |
printf("break at %08X\n", addr); |
showPC(); |
} |
|
|
static void doStep(char *tokens[], int n) { |
Word count, i; |
|
if (n == 1) { |
count = 1; |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &count) || count == 0) { |
printf("illegal count\n"); |
return; |
} |
} else { |
help06(); |
return; |
} |
for (i = 0; i < count; i++) { |
cpuStep(); |
} |
showPC(); |
} |
|
|
static void doPC(char *tokens[], int n) { |
Word addr; |
|
if (n == 1) { |
showPC(); |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
addr &= ~0x00000003; |
cpuSetPC(addr); |
showPC(); |
} else { |
help07(); |
} |
} |
|
|
static void explainPSW(Word data) { |
int i; |
|
printf("interrupt vector : %s (%s)\n", |
data & PSW_V ? "on " : "off", |
data & PSW_V ? "RAM" : "ROM"); |
printf("current user mode : %s (%s)\n", |
data & PSW_UM ? "on " : "off", |
data & PSW_UM ? "user" : "kernel"); |
printf("previous user mode : %s (%s)\n", |
data & PSW_PUM ? "on " : "off", |
data & PSW_PUM ? "user" : "kernel"); |
printf("old user mode : %s (%s)\n", |
data & PSW_OUM ? "on " : "off", |
data & PSW_OUM ? "user" : "kernel"); |
printf("current interrupt enable : %s (%s)\n", |
data & PSW_IE ? "on " : "off", |
data & PSW_IE ? "enabled" : "disabled"); |
printf("previous interrupt enable : %s (%s)\n", |
data & PSW_PIE ? "on " : "off", |
data & PSW_PIE ? "enabled" : "disabled"); |
printf("old interrupt enable : %s (%s)\n", |
data & PSW_OIE ? "on " : "off", |
data & PSW_OIE ? "enabled" : "disabled"); |
printf("last interrupt acknowledged : %02X (%s)\n", |
(data & PSW_PRIO_MASK) >> 16, |
exceptionToString((data & PSW_PRIO_MASK) >> 16)); |
for (i = 15; i >= 0; i--) { |
printf("%-35s: %s (%s)\n", |
exceptionToString(i), |
data & (1 << i) ? "on " : "off", |
data & (1 << i) ? "enabled" : "disabled"); |
} |
} |
|
|
static void doPSW(char *tokens[], int n) { |
Word data; |
|
if (n == 1) { |
data = cpuGetPSW(); |
showPSW(); |
explainPSW(data); |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &data)) { |
printf("illegal data\n"); |
return; |
} |
data &= 0x0FFFFFFF; |
cpuSetPSW(data); |
showPSW(); |
explainPSW(data); |
} else { |
help08(); |
} |
} |
|
|
static void doRegister(char *tokens[], int n) { |
int i, j; |
int reg; |
Word data; |
|
if (n == 1) { |
for (i = 0; i < 8; i++) { |
for (j = 0; j < 4; j++) { |
reg = 8 * j + i; |
data = cpuGetReg(reg); |
printf("$%-2d %08X ", reg, data); |
} |
printf("\n"); |
} |
showPSW(); |
showBreak(); |
showPC(); |
} else if (n == 2) { |
if (!getDecNumber(tokens[1], ®) || reg < 0 || reg >= 32) { |
printf("illegal register number\n"); |
return; |
} |
data = cpuGetReg(reg); |
printf("$%-2d %08X\n", reg, data); |
} else if (n == 3) { |
if (!getDecNumber(tokens[1], ®) || reg < 0 || reg >= 32) { |
printf("illegal register number\n"); |
return; |
} |
if (!getHexNumber(tokens[2], &data)) { |
printf("illegal data\n"); |
return; |
} |
cpuSetReg(reg, data); |
} else { |
help09(); |
} |
} |
|
|
static void doDump(char *tokens[], int n) { |
Word addr, count; |
Word psw; |
Word lo, hi, curr; |
int lines, i, j; |
Word tmp; |
Byte c; |
|
if (n == 1) { |
addr = cpuGetPC(); |
count = 16 * 16; |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
count = 16 * 16; |
} else if (n == 3) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
if (!getHexNumber(tokens[2], &count)) { |
printf("illegal count\n"); |
return; |
} |
if (count == 0) { |
return; |
} |
} else { |
help10(); |
return; |
} |
psw = cpuGetPSW(); |
lo = addr & ~0x0000000F; |
hi = addr + count - 1; |
if (hi < lo) { |
/* wrap-around */ |
hi = 0xFFFFFFFF; |
} |
lines = (hi - lo + 16) >> 4; |
curr = lo; |
for (i = 0; i < lines; i++) { |
printf("%08X: ", curr); |
for (j = 0; j < 16; j++) { |
tmp = curr + j; |
if (tmp < addr || tmp > hi) { |
printf(" "); |
} else { |
c = mmuReadByte(tmp); |
printf("%02X", c); |
} |
printf(" "); |
} |
printf(" "); |
for (j = 0; j < 16; j++) { |
tmp = curr + j; |
if (tmp < addr || tmp > hi) { |
printf(" "); |
} else { |
c = mmuReadByte(tmp); |
if (c >= 32 && c <= 126) { |
printf("%c", c); |
} else { |
printf("."); |
} |
} |
} |
printf("\n"); |
curr += 16; |
} |
} |
|
|
static void doMemoryWord(char *tokens[], int n) { |
Word psw; |
Word addr; |
Word data; |
Word tmpData; |
|
psw = cpuGetPSW(); |
if (n == 1) { |
addr = cpuGetPC(); |
data = mmuReadWord(addr); |
printf("%08X: %08X\n", addr, data); |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
data = mmuReadWord(addr); |
printf("%08X: %08X\n", addr, data); |
} else if (n == 3) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
if (!getHexNumber(tokens[2], &tmpData)) { |
printf("illegal data\n"); |
return; |
} |
data = tmpData; |
mmuWriteWord(addr, data); |
} else { |
help11(); |
} |
} |
|
|
static void doMemoryHalf(char *tokens[], int n) { |
Word psw; |
Word addr; |
Half data; |
Word tmpData; |
|
psw = cpuGetPSW(); |
if (n == 1) { |
addr = cpuGetPC(); |
data = mmuReadHalf(addr); |
printf("%08X: %04X\n", addr, data); |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
data = mmuReadHalf(addr); |
printf("%08X: %04X\n", addr, data); |
} else if (n == 3) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
if (!getHexNumber(tokens[2], &tmpData)) { |
printf("illegal data\n"); |
return; |
} |
data = (Half) tmpData; |
mmuWriteHalf(addr, data); |
} else { |
help12(); |
} |
} |
|
|
static void doMemoryByte(char *tokens[], int n) { |
Word psw; |
Word addr; |
Byte data; |
Word tmpData; |
|
psw = cpuGetPSW(); |
if (n == 1) { |
addr = cpuGetPC(); |
data = mmuReadByte(addr); |
printf("%08X: %02X\n", addr, data); |
} else if (n == 2) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
data = mmuReadByte(addr); |
printf("%08X: %02X\n", addr, data); |
} else if (n == 3) { |
if (!getHexNumber(tokens[1], &addr)) { |
printf("illegal address\n"); |
return; |
} |
if (!getHexNumber(tokens[2], &tmpData)) { |
printf("illegal data\n"); |
return; |
} |
data = (Byte) tmpData; |
mmuWriteByte(addr, data); |
} else { |
help13(); |
} |
} |
|
|
static void doTLB(char *tokens[], int n) { |
static char *mmuAccsWidth[4] = { "byte", "half", "word", "????" }; |
int index; |
TLB_Entry tlbEntry; |
Word mmuAccs; |
Word data; |
|
if (n == 1) { |
for (index = 0; index < TLB_SIZE; index++) { |
tlbEntry = mmuGetTLB(index); |
printf("TLB[%02d] page %08X frame %08X %c %c\n", |
index, tlbEntry.page, tlbEntry.frame, |
tlbEntry.write ? 'w' : '-', |
tlbEntry.valid ? 'v' : '-'); |
} |
printf("Index (1) %08X\n", mmuGetIndex()); |
printf("EntryHi (2) %08X\n", mmuGetEntryHi()); |
printf("EntryLo (3) %08X\n", mmuGetEntryLo()); |
printf("BadAddr (4) %08X\n", mmuGetBadAddr()); |
mmuAccs = mmuGetBadAccs(); |
printf("BadAccs (5) %08X (%s %s)\n", |
mmuAccs, |
(mmuAccs & MMU_ACCS_WRITE) ? "write" : "read", |
mmuAccsWidth[mmuAccs & 0x03]); |
} else if (n == 2) { |
if (!getDecNumber(tokens[1], &index) || index < 0 || index >= TLB_SIZE) { |
printf("illegal TLB index\n"); |
return; |
} |
tlbEntry = mmuGetTLB(index); |
printf("TLB[%02d] page %08X frame %08X %c %c\n", |
index, tlbEntry.page, tlbEntry.frame, |
tlbEntry.write ? 'w' : '-', |
tlbEntry.valid ? 'v' : '-'); |
} else if (n == 3) { |
help14(); |
} else if (n == 4) { |
if (!getDecNumber(tokens[1], &index) || index < 0 || index >= TLB_SIZE) { |
printf("illegal TLB index\n"); |
return; |
} |
if (!getHexNumber(tokens[3], &data)) { |
printf("illegal data\n"); |
return; |
} |
tlbEntry = mmuGetTLB(index); |
if (strcmp(tokens[2], "p") == 0) { |
tlbEntry.page = data & PAGE_MASK; |
} else |
if (strcmp(tokens[2], "f") == 0) { |
tlbEntry.frame = data & PAGE_MASK; |
tlbEntry.write = data & TLB_WRITE ? true : false; |
tlbEntry.valid = data & TLB_VALID ? true : false; |
} else { |
printf("TLB selector is not one of 'p' or 'f'\n"); |
return; |
} |
mmuSetTLB(index, tlbEntry); |
printf("TLB[%02d] page %08X frame %08X %c %c\n", |
index, tlbEntry.page, tlbEntry.frame, |
tlbEntry.write ? 'w' : '-', |
tlbEntry.valid ? 'v' : '-'); |
} else { |
help14(); |
} |
} |
|
|
static void doLoad(char *tokens[], int n) { |
int serno; |
|
if (n == 2) { |
if (!getDecNumber(tokens[1], &serno) || serno < 0 || serno > 1) { |
printf("illegal serial line number\n"); |
return; |
} |
load(serno, true); |
} else if (n == 3) { |
if (!getDecNumber(tokens[1], &serno) || serno < 0 || serno > 1) { |
printf("illegal serial line number\n"); |
return; |
} |
if (strcmp(tokens[2], "*") != 0) { |
help15(); |
return; |
} |
load(serno, false); |
} else { |
help15(); |
} |
} |
|
|
static void doBoot(char *tokens[], int n) { |
int dskno; |
|
if (n == 2) { |
if (!getDecNumber(tokens[1], &dskno) || dskno < 0 || dskno > 1) { |
printf("illegal disk number\n"); |
return; |
} |
boot(dskno, true); |
} else if (n == 3) { |
if (!getDecNumber(tokens[1], &dskno) || dskno < 0 || dskno > 1) { |
printf("illegal disk number\n"); |
return; |
} |
if (strcmp(tokens[2], "*") != 0) { |
help16(); |
return; |
} |
boot(dskno, false); |
} else { |
help16(); |
} |
} |
|
|
Command commands[] = { |
{ "help", help00, doHelp }, |
{ "+", help01, doArith }, |
{ "a", help02, doAssemble }, |
{ "u", help03, doUnassemble }, |
{ "b", help04, doBreak }, |
{ "c", help05, doContinue }, |
{ "s", help06, doStep }, |
{ "#", help07, doPC }, |
{ "p", help08, doPSW }, |
{ "r", help09, doRegister }, |
{ "d", help10, doDump }, |
{ "mw", help11, doMemoryWord }, |
{ "mh", help12, doMemoryHalf }, |
{ "mb", help13, doMemoryByte }, |
{ "t", help14, doTLB }, |
{ "load", help15, doLoad }, |
{ "boot", help16, doBoot }, |
}; |
|
int numCommands = sizeof(commands) / sizeof(commands[0]); |
|
|
static void doCommand(char *line) { |
char *tokens[MAX_TOKENS]; |
int n; |
char *p; |
int i; |
|
n = 0; |
p = strtok(line, " \t\n"); |
while (p != NULL) { |
if (n == MAX_TOKENS) { |
printf("too many tokens on line\n"); |
return; |
} |
tokens[n++] = p; |
p = strtok(NULL, " \t\n"); |
} |
if (n == 0) { |
return; |
} |
for (i = 0; i < numCommands; i++) { |
if (strcmp(commands[i].name, tokens[0]) == 0) { |
(*commands[i].cmdProc)(tokens, n); |
return; |
} |
} |
help(); |
} |
|
|
static char *article(char firstLetterOfNoun) { |
switch (firstLetterOfNoun) { |
case 'a': |
case 'e': |
case 'i': |
case 'o': |
case 'u': |
return "An"; |
default: |
return "A"; |
} |
} |
|
|
static void interactiveException(int exception) { |
char *what; |
|
what = exceptionToString(exception); |
printf("\n"); |
printf("NOTE: %s %s occurred while executing the command.\n", |
article(*what), what); |
printf(" This event will not alter the state of the CPU.\n"); |
} |
|
|
void execCommand(char *line) { |
MonitorState commandState; |
|
if (saveState(&commandState)) { |
/* initialization */ |
monitorReturn = &commandState; |
doCommand(line); |
} else { |
/* an exception was thrown */ |
interactiveException((userContext.psw & PSW_PRIO_MASK) >> 16); |
} |
monitorReturn = NULL; |
} |
/common/load.c
0,0 → 1,226
/* |
* load.c -- load S-records from serial line |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "load.h" |
#include "serial.h" |
#include "cpu.h" |
#include "mmu.h" |
|
|
#define NUM_TRIES 10 |
#define WAIT_DELAY 350000 |
|
#define SYN ((unsigned char) 's') |
#define ACK ((unsigned char) 'a') |
|
#define LINE_SIZE 520 |
|
|
static Byte line[LINE_SIZE]; |
|
|
static Word getByte(int index) { |
Word hi, lo; |
|
hi = line[index + 0]; |
if (hi >= '0' && hi <= '9') { |
hi -= '0'; |
} else |
if (hi >= 'A' && hi <= 'F') { |
hi -= 'A' - 10; |
} else |
if (hi >= 'a' && hi <= 'f') { |
hi -= 'a' - 10; |
} else { |
return -1; |
} |
lo = line[index + 1]; |
if (lo >= '0' && lo <= '9') { |
lo -= '0'; |
} else |
if (lo >= 'A' && lo <= 'F') { |
lo -= 'A' - 10; |
} else |
if (lo >= 'a' && lo <= 'f') { |
lo -= 'a' - 10; |
} else { |
return -1; |
} |
return (hi << 4) | lo; |
} |
|
|
static void serialOut(int serno, Word c) { |
if (serno == 0) { |
ser0out(c); |
} else { |
ser1out(c); |
} |
} |
|
|
static int serialChk(int serno) { |
if (serno == 0) { |
return ser0inchk(); |
} else { |
return ser1inchk(); |
} |
} |
|
|
static Word serialIn(int serno) { |
if (serno == 0) { |
return ser0in(); |
} else { |
return ser1in(); |
} |
} |
|
|
void load(int serno, Bool start) { |
int i, j; |
Bool run; |
int type; |
int count; |
Word chksum; |
Word addr; |
Byte b; |
|
printf("Trying to connect to load server...\n"); |
for (i = 0; i < NUM_TRIES; i++) { |
serialOut(serno, SYN); |
for (j = 0; j < WAIT_DELAY; j++) { |
if (serialChk(serno) != 0) { |
break; |
} |
} |
if (j < WAIT_DELAY) { |
break; |
} |
printf("Request timed out...\n"); |
} |
if (i == NUM_TRIES || |
serialIn(serno) != ACK) { |
printf("Unable to establish connection to load server.\n"); |
return; |
} |
serialOut(serno, ACK); |
printf("Connected to load server.\n"); |
run = true; |
while (run) { |
serialOut(serno, 'r'); |
for (i = 0; i < LINE_SIZE; i++) { |
line[i] = serialIn(serno); |
if (line[i] == '\n') { |
break; |
} |
} |
if (i == LINE_SIZE) { |
printf("Error: too many characters in S-record!\n"); |
break; |
} |
line[i] = '\0'; |
printf("%s\n", line); |
if (line[0] != 'S') { |
printf("Error: malformed S-record!\n"); |
break; |
} |
type = line[1]; |
count = getByte(2); |
if (i != 2 * count + 4) { |
printf("Error: inconsistent byte count in S-record!\n"); |
break; |
} |
chksum = 0; |
for (j = 2; j < i; j += 2) { |
chksum += getByte(j); |
} |
if ((chksum & 0xFF) != 0xFF) { |
printf("Error: wrong checksum in S-record!\n"); |
break; |
} |
switch (type) { |
case '0': |
/* S0 record: header (skip) */ |
break; |
case '1': |
/* S1 record: 2 byte load address + data (load data) */ |
addr = (getByte( 4) << 8) | |
(getByte( 6) << 0); |
addr |= 0xC0000000; |
for (j = 0; j < count - 3; j++) { |
b = getByte(2 * j + 8); |
mmuWriteByte(addr + j, b); |
} |
break; |
case '2': |
/* S2 record: 3 byte load address + data (load data) */ |
addr = (getByte( 4) << 16) | |
(getByte( 6) << 8) | |
(getByte( 8) << 0); |
addr |= 0xC0000000; |
for (j = 0; j < count - 4; j++) { |
b = getByte(2 * j + 10); |
mmuWriteByte(addr + j, b); |
} |
break; |
case '3': |
/* S3 record: 4 byte load address + data (load data) */ |
addr = (getByte( 4) << 24) | |
(getByte( 6) << 16) | |
(getByte( 8) << 8) | |
(getByte(10) << 0); |
addr |= 0xC0000000; |
for (j = 0; j < count - 5; j++) { |
b = getByte(2 * j + 12); |
mmuWriteByte(addr + j, b); |
} |
break; |
case '5': |
/* S5 record: record count (skip) */ |
break; |
case '7': |
/* S7 record: 4 byte start address (set PC, stop loading) */ |
addr = (getByte( 4) << 24) | |
(getByte( 6) << 16) | |
(getByte( 8) << 8) | |
(getByte(10) << 0); |
addr |= 0xC0000000; |
cpuSetPC(addr); |
run = false; |
break; |
case '8': |
/* S8 record: 3 byte start address (set PC, stop loading) */ |
addr = (getByte( 4) << 16) | |
(getByte( 6) << 8) | |
(getByte( 8) << 0); |
addr |= 0xC0000000; |
cpuSetPC(addr); |
run = false; |
break; |
case '9': |
/* S9 record: 2 byte start address (set PC, stop loading) */ |
addr = (getByte( 4) << 8) | |
(getByte( 6) << 0); |
addr |= 0xC0000000; |
cpuSetPC(addr); |
run = false; |
break; |
default: |
/* unknown type of S-record */ |
printf("Error: unknown type of S-record!\n"); |
run = false; |
break; |
} |
} |
serialOut(serno, 'q'); |
printf("Connection to load server closed.\n"); |
if (start) { |
cpuRun(); |
} |
} |
/common/load.h
0,0 → 1,13
/* |
* load.h -- load S-records from serial line |
*/ |
|
|
#ifndef _LOAD_H_ |
#define _LOAD_H_ |
|
|
void load(int serno, Bool start); |
|
|
#endif /* _LOAD_H_ */ |
/common/main.c
0,0 → 1,32
/* |
* main.c -- the main program |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "command.h" |
#include "getline.h" |
#include "instr.h" |
#include "cpu.h" |
|
|
#define VERSION "1.06" |
#define PROMPT "ECO32 > " |
|
|
int main(void) { |
char *line; |
|
printf("\n\nECO32 Machine Monitor %s\n\n", VERSION); |
initInstrTable(); |
cpuSetPC(0xC0010000); |
cpuSetPSW(0x08000000); |
while (1) { |
line = getLine(PROMPT); |
addHist(line); |
execCommand(line); |
} |
return 0; |
} |
/common/boot.c
0,0 → 1,48
/* |
* boot.c -- bootstrap from disk |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "boot.h" |
#include "cpu.h" |
#include "mmu.h" |
#include "start.h" |
|
|
void boot(int dskno, Bool start) { |
Word capacity; |
Byte sig1, sig2; |
|
capacity = dskcap(dskno); |
if (capacity == 0) { |
printf("Disk not found!\n"); |
return; |
} |
printf("Disk with 0x%08X sectors found, booting...\n", capacity); |
if (dskio(dskno, 'r', 0, PHYS_BOOT, 1) != 0) { |
printf("Disk error!\n"); |
return; |
} |
sig1 = mmuReadByte(VIRT_BOOT + 512 - 2); |
sig2 = mmuReadByte(VIRT_BOOT + 512 - 1); |
if (sig1 != 0x55 || sig2 != 0xAA) { |
printf("MBR signature missing!\n"); |
return; |
} |
/* |
* Boot convention: |
* $16 disk number of boot disk |
* $17 start sector number of disk or partition to boot |
* $18 total number of sectors of disk or partition to boot |
*/ |
cpuSetReg(16, dskno); |
cpuSetReg(17, 0); |
cpuSetReg(18, capacity); |
cpuSetPC(VIRT_BOOT); |
if (start) { |
cpuRun(); |
} |
} |
/common/boot.h
0,0 → 1,17
/* |
* boot.h -- bootstrap from disk |
*/ |
|
|
#ifndef _BOOT_H_ |
#define _BOOT_H_ |
|
|
#define PHYS_BOOT 0x00010000 /* where to load the bootstrap */ |
#define VIRT_BOOT 0xC0010000 /* where to start the bootstrap */ |
|
|
void boot(int dskno, Bool start); |
|
|
#endif /* _BOOT_H_ */ |
/common/cpu.c
0,0 → 1,365
/* |
* cpu.c -- execute instructions |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "instr.h" |
#include "cpu.h" |
#include "mmu.h" |
#include "start.h" |
|
|
#define RR(n) r[n] |
#define WR(n,d) ((void) ((n) != 0 ? r[n] = (d) : (d))) |
|
#define BREAK ((OP_TRAP << 26) | 0x0001) |
|
|
/**************************************************************/ |
|
|
static Word pc; /* program counter */ |
static Word psw; /* processor status word */ |
static Word r[32]; /* general purpose registers */ |
|
static Bool breakSet; /* breakpoint set if true */ |
static Word breakAddr; /* if breakSet, this is where */ |
|
|
/**************************************************************/ |
|
|
Word cpuGetPC(void) { |
return pc; |
} |
|
|
void cpuSetPC(Word addr) { |
pc = addr; |
} |
|
|
Word cpuGetReg(int regnum) { |
return RR(regnum & 0x1F); |
} |
|
|
void cpuSetReg(int regnum, Word value) { |
WR(regnum & 0x1F, value); |
} |
|
|
Word cpuGetPSW(void) { |
return psw; |
} |
|
|
void cpuSetPSW(Word value) { |
psw = value; |
} |
|
|
Bool cpuTestBreak(void) { |
return breakSet; |
} |
|
|
Word cpuGetBreak(void) { |
return breakAddr; |
} |
|
|
void cpuSetBreak(Word addr) { |
breakAddr = addr; |
breakSet = true; |
} |
|
|
void cpuResetBreak(void) { |
breakSet = false; |
} |
|
|
/**************************************************************/ |
|
|
static char *cause[32] = { |
/* 0 */ "serial line 0 xmt interrupt", |
/* 1 */ "serial line 0 rcv interrupt", |
/* 2 */ "serial line 1 xmt interrupt", |
/* 3 */ "serial line 1 rcv interrupt", |
/* 4 */ "keyboard interrupt", |
/* 5 */ "unknown interrupt", |
/* 6 */ "unknown interrupt", |
/* 7 */ "unknown interrupt", |
/* 8 */ "disk interrupt", |
/* 9 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer 0 interrupt", |
/* 15 */ "timer 1 interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
char *exceptionToString(int exception) { |
if (exception < 0 || |
exception >= sizeof(cause)/sizeof(cause[0])) { |
return "<exception number out of bounds>"; |
} |
return cause[exception]; |
} |
|
|
/**************************************************************/ |
|
|
static Byte stepType[64] = { |
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ |
/* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
/* 0x10 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
/* 0x20 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 3, 4, 1, 0, |
/* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
}; |
|
|
static Bool evalCond(int cc, Word a, Word b) { |
switch (cc) { |
case 0: |
/* equal */ |
if (a == b) { |
return true; |
} |
break; |
case 1: |
/* not equal */ |
if (a != b) { |
return true; |
} |
break; |
case 2: |
/* less or equal (signed) */ |
if ((signed int) a <= (signed int) b) { |
return true; |
} |
break; |
case 3: |
/* less or equal (unsigned) */ |
if (a <= b) { |
return true; |
} |
break; |
case 4: |
/* less than (signed) */ |
if ((signed int) a < (signed int) b) { |
return true; |
} |
break; |
case 5: |
/* less than (unsigned) */ |
if (a < b) { |
return true; |
} |
break; |
case 6: |
/* greater or equal (signed) */ |
if ((signed int) a >= (signed int) b) { |
return true; |
} |
break; |
case 7: |
/* greater or equal (unsigned) */ |
if (a >= b) { |
return true; |
} |
break; |
case 8: |
/* greater than (signed) */ |
if ((signed int) a > (signed int) b) { |
return true; |
} |
break; |
case 9: |
/* greater than (unsigned) */ |
if (a > b) { |
return true; |
} |
break; |
default: |
/* this should never happen */ |
printf("cannot compute condition code %d\n", cc); |
break; |
} |
return false; |
} |
|
|
void cpuStep(void) { |
Word instr; |
int opcode; |
int reg1, reg2; |
Half immed; |
Word offset; |
Word nextAddr; |
Word nextInstr; |
int i; |
MonitorState stepState; |
MonitorState *origReturn; |
|
instr = mmuReadWord(pc); |
opcode = (instr >> 26) & 0x3F; |
reg1 = (instr >> 21) & 0x1F; |
reg2 = (instr >> 16) & 0x1F; |
immed = instr & 0x0000FFFF; |
offset = instr & 0x03FFFFFF; |
switch (stepType[opcode]) { |
case 1: |
/* next instruction follows current one immediately */ |
nextAddr = pc + 4; |
break; |
case 2: |
/* next instruction conditionally reached by PC relative branch */ |
nextAddr = pc + 4; |
if (evalCond(opcode - OP_BEQ, RR(reg1), RR(reg2))) { |
nextAddr += SEXT16(immed) << 2; |
} |
break; |
case 3: |
/* next instruction reached by PC relative jump */ |
nextAddr = pc + 4 + (SEXT26(offset) << 2); |
break; |
case 4: |
/* next instruction reached by jump to register contents */ |
nextAddr = RR(reg1) & 0xFFFFFFFC; |
break; |
default: |
printf("cannot single-step instruction with opcode 0x%02X\n", |
opcode); |
return; |
} |
nextInstr = mmuReadWord(nextAddr); |
mmuWriteWord(nextAddr, BREAK); |
for (i = 0; i < 32; i++) { |
userContext.reg[i] = RR(i); |
} |
userContext.reg[30] = pc; |
userContext.psw = psw; |
userContext.tlbIndex = mmuGetIndex(); |
userContext.tlbHi = mmuGetEntryHi(); |
userContext.tlbLo = mmuGetEntryLo(); |
userContext.badAddr = mmuGetBadAddr(); |
userContext.badAccs = mmuGetBadAccs(); |
if (saveState(&stepState)) { |
origReturn = monitorReturn; |
monitorReturn = &stepState; |
resume(); |
} |
monitorReturn = origReturn; |
for (i = 0; i < 32; i++) { |
WR(i, userContext.reg[i]); |
} |
pc = userContext.reg[30]; |
psw = userContext.psw; |
mmuSetIndex(userContext.tlbIndex); |
mmuSetEntryHi(userContext.tlbHi); |
mmuSetEntryLo(userContext.tlbLo); |
mmuSetBadAddr(userContext.badAddr); |
mmuSetBadAccs(userContext.badAccs); |
mmuWriteWord(nextAddr, nextInstr); |
if (nextAddr == pc) { |
return; |
} |
if ((psw & PSW_PRIO_MASK) >> 16 == 21 && |
(mmuGetEntryHi() & 0x80000000) == 0) { |
/* TLB user miss */ |
printf("unexpected TLB user miss exception occurred\n"); |
return; |
} else { |
/* any other exception */ |
printf("unexpected %s occurred\n", |
exceptionToString((psw & PSW_PRIO_MASK) >> 16)); |
return; |
} |
} |
|
|
void cpuRun(void) { |
Word instr; |
int i; |
MonitorState runState; |
MonitorState *origReturn; |
|
if (breakSet && breakAddr == pc) { |
/* single-step one instruction */ |
cpuStep(); |
} |
while (1) { |
if (breakSet) { |
instr = mmuReadWord(breakAddr); |
mmuWriteWord(breakAddr, BREAK); |
} |
for (i = 0; i < 32; i++) { |
userContext.reg[i] = RR(i); |
} |
userContext.reg[30] = pc; |
userContext.psw = psw; |
userContext.tlbIndex = mmuGetIndex(); |
userContext.tlbHi = mmuGetEntryHi(); |
userContext.tlbLo = mmuGetEntryLo(); |
userContext.badAddr = mmuGetBadAddr(); |
userContext.badAccs = mmuGetBadAccs(); |
if (saveState(&runState)) { |
origReturn = monitorReturn; |
monitorReturn = &runState; |
resume(); |
} |
monitorReturn = origReturn; |
for (i = 0; i < 32; i++) { |
WR(i, userContext.reg[i]); |
} |
pc = userContext.reg[30]; |
psw = userContext.psw; |
mmuSetIndex(userContext.tlbIndex); |
mmuSetEntryHi(userContext.tlbHi); |
mmuSetEntryLo(userContext.tlbLo); |
mmuSetBadAddr(userContext.badAddr); |
mmuSetBadAccs(userContext.badAccs); |
if (breakSet) { |
mmuWriteWord(breakAddr, instr); |
} |
if (breakSet && breakAddr == pc) { |
return; |
} |
if ((psw & PSW_PRIO_MASK) >> 16 == 21 && |
(mmuGetEntryHi() & 0x80000000) == 0) { |
/* TLB user miss */ |
printf("unexpected TLB user miss exception occurred\n"); |
return; |
} else { |
/* any other exception */ |
printf("unexpected %s occurred\n", |
exceptionToString((psw & PSW_PRIO_MASK) >> 16)); |
return; |
} |
} |
} |
/common/start.h
0,0 → 1,55
/* |
* start.h -- ECO32 ROM monitor startup and support routines |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef struct { |
Word reg[32]; /* general purpose registers */ |
Word psw; /* PSW */ |
Word tlbIndex; /* TLB index register */ |
Word tlbHi; /* TLB EntryHi register */ |
Word tlbLo; /* TLB EntryLo register */ |
Word badAddr; /* bad address register */ |
Word badAccs; /* bad access register */ |
} UserContext; |
|
typedef struct { |
Word r31; /* return address */ |
Word r29; /* stack pointer */ |
Word r16; /* local variable */ |
Word r17; /* local variable */ |
Word r18; /* local variable */ |
Word r19; /* local variable */ |
Word r20; /* local variable */ |
Word r21; /* local variable */ |
Word r22; /* local variable */ |
Word r23; /* local variable */ |
} MonitorState; |
|
|
void setcon(Byte ctl); |
int cinchk(void); |
char cin(void); |
int coutchk(void); |
void cout(char c); |
|
int dskcap(int dskno); |
int dskio(int dskno, char cmd, int sct, Word addr, int nscts); |
|
Word getTLB_HI(int index); |
Word getTLB_LO(int index); |
void setTLB(int index, Word entryHi, Word entryLo); |
|
Bool saveState(MonitorState *msp); |
|
extern MonitorState *monitorReturn; |
extern UserContext userContext; |
|
void resume(void); |
|
|
#endif /* _START_H_ */ |
/common/dskctl.s
0,0 → 1,137
; |
; dskctl.s -- disk made available by disk controller |
; |
|
;*************************************************************** |
|
.set dskbase,0xF0400000 ; disk base address |
.set dskctrl,0 ; control register |
.set dskcnt,4 ; count register |
.set dsksct,8 ; sector register |
.set dskcap,12 ; capacity register |
.set dskbuf,0x00080000 ; disk buffer |
|
.set ctrlstrt,0x01 ; start bit |
.set ctrlien,0x02 ; interrupt enable bit |
.set ctrlwrt,0x04 ; write bit |
.set ctrlerr,0x08 ; error bit |
.set ctrldone,0x10 ; done bit |
.set ctrlrdy,0x20 ; ready bit |
|
.set sctsize,512 ; sector size in bytes |
|
.set retries,1000000 ; retries to get disk ready |
|
.export dskinitctl ; initialize disk |
.export dskcapctl ; determine disk capacity |
.export dskioctl ; do disk I/O |
|
;*************************************************************** |
|
.code |
.align 4 |
|
dskinitctl: |
jr $31 |
|
dskcapctl: |
add $8,$0,retries ; set retry count |
add $9,$0,dskbase |
dskcap1: |
ldw $10,$9,dskctrl |
and $10,$10,ctrlrdy ; ready? |
bne $10,$0,dskcapok ; yes - jump |
sub $8,$8,1 |
bne $8,$0,dskcap1 ; try again |
add $2,$0,0 ; no disk found |
j dskcapx |
dskcapok: |
ldw $2,$9,dskcap ; get disk capacity |
dskcapx: |
jr $31 |
|
dskioctl: |
sub $29,$29,24 |
stw $31,$29,20 |
stw $16,$29,16 |
stw $17,$29,12 |
stw $18,$29,8 |
stw $19,$29,4 |
stw $20,$29,0 |
add $16,$4,$0 ; command |
add $17,$5,$0 ; sector number |
add $18,$6,0xC0000000 ; memory address, virtualized |
add $19,$7,$0 ; number of sectors |
|
add $8,$0,'r' |
beq $16,$8,dskrd |
add $8,$0,'w' |
beq $16,$8,dskwr |
add $2,$0,0xFF ; illegal command |
j dskx |
|
dskrd: |
add $2,$0,$0 ; return ok |
beq $19,$0,dskx ; if no (more) sectors |
add $8,$0,dskbase |
add $9,$0,1 |
stw $9,$8,dskcnt ; number of sectors |
stw $17,$8,dsksct ; sector number on disk |
add $9,$0,ctrlstrt |
stw $9,$8,dskctrl ; start command |
dskrd1: |
ldw $2,$8,dskctrl |
and $9,$2,ctrldone ; done? |
beq $9,$0,dskrd1 ; no - wait |
and $9,$2,ctrlerr ; error? |
bne $9,$0,dskx ; yes - leave |
add $8,$0,dskbase + dskbuf ; transfer data |
add $9,$0,sctsize |
dskrd2: |
ldw $10,$8,0 ; from disk buffer |
stw $10,$18,0 ; to memory |
add $8,$8,4 |
add $18,$18,4 |
sub $9,$9,4 |
bne $9,$0,dskrd2 |
add $17,$17,1 ; increment sector number |
sub $19,$19,1 ; decrement number of sectors |
j dskrd ; next sector |
|
dskwr: |
add $2,$0,$0 ; return ok |
beq $19,$0,dskx ; if no (more) sectors |
add $8,$0,dskbase + dskbuf ; transfer data |
add $9,$0,sctsize |
dskwr1: |
ldw $10,$18,0 ; from memory |
stw $10,$8,0 ; to disk buffer |
add $18,$18,4 |
add $8,$8,4 |
sub $9,$9,4 |
bne $9,$0,dskwr1 |
add $8,$0,dskbase |
add $9,$0,1 |
stw $9,$8,dskcnt ; number of sectors |
stw $17,$8,dsksct ; sector number on disk |
add $9,$0,ctrlwrt | ctrlstrt |
stw $9,$8,dskctrl ; start command |
dskwr2: |
ldw $2,$8,dskctrl |
and $9,$2,ctrldone ; done? |
beq $9,$0,dskwr2 ; no - wait |
and $9,$2,ctrlerr ; error? |
bne $9,$0,dskx ; yes - leave |
add $17,$17,1 ; increment sector number |
sub $19,$19,1 ; decrement number of sectors |
j dskwr ; next sector |
|
dskx: |
ldw $20,$29,0 |
ldw $19,$29,4 |
ldw $18,$29,8 |
ldw $17,$29,12 |
ldw $16,$29,16 |
ldw $31,$29,20 |
add $29,$29,24 |
jr $31 |
/common/dskser.s
0,0 → 1,204
; |
; dskser.s -- disk made available by serial interface |
; |
|
;*************************************************************** |
|
.export dskinitser ; initialize disk |
.export dskcapser ; determine disk capacity |
.export dskioser ; do disk I/O |
|
.import ser1in |
.import ser1out |
.import ser1inchk |
.import puts |
|
; constants for communication with disk server |
.set SYN,0x16 ; to initiate the three-way handshake |
.set ACK,0x06 ; acknowledgement for handshake |
.set RESULT_OK,0x00 ; server successfully executed cmd |
; everything else means error |
|
.set WAIT_DELAY,800000 ; count for delay loop |
|
;*************************************************************** |
|
.code |
.align 4 |
|
dskinitser: |
jr $31 |
|
dskcapser: |
sub $29,$29,16 |
stw $16,$29,0 |
stw $17,$29,4 |
stw $18,$29,8 |
stw $31,$29,12 |
add $4,$0,trymsg ; say what we are doing |
jal puts |
add $18,$0,$0 ; capacity == 0 if disk not present |
add $16,$0,10 ; 10 tries to get a connection |
handshake1: |
sub $16,$16,1 |
add $4,$0,SYN |
jal ser1out ; send SYN |
add $17,$0,WAIT_DELAY ; wait for ACK |
handshake2: |
sub $17,$17,1 |
jal ser1inchk |
bne $2,$0,handshake3 |
bne $17,$0,handshake2 |
add $4,$0,timeoutmsg |
jal puts |
bne $16,$0,handshake1 |
add $4,$0,frustratedmsg |
jal puts |
j dskcapx |
handshake3: |
jal ser1in |
add $8,$0,ACK |
bne $2,$8,dskcapx |
; we got an ACK so we return it |
add $4,$0,ACK |
jal ser1out |
|
; ask it for its capacity |
add $4,$0,'c' |
jal ser1out ; request |
jal ser1in ; first byte of response |
bne $2,$0,dskcapx ; exit if error |
|
; all is well and the server will give us the capacity |
add $16,$0,4 ; 4 bytes to read |
dskcap1: |
sll $18,$18,8 |
jal ser1in |
or $18,$18,$2 ; most significant byte first |
sub $16,$16,1 |
bne $16,$0,dskcap1 |
|
; return value is in $18 |
dskcapx: |
add $2,$0,$18 |
ldw $16,$29,0 |
ldw $17,$29,4 |
ldw $18,$29,8 |
ldw $31,$29,12 |
add $29,$29,16 |
jr $31 |
|
.data |
.align 4 |
|
trymsg: |
.byte "Trying to connect to disk server..." |
.byte 0x0A, 0 |
|
timeoutmsg: |
.byte "Request timed out..." |
.byte 0x0A, 0 |
|
frustratedmsg: |
.byte "Unable to establish connection to disk server." |
.byte 0x0A, 0 |
|
.code |
.align 4 |
|
dskioser: |
sub $29,$29,24 |
stw $16,$29,0 |
stw $17,$29,4 |
stw $18,$29,8 |
stw $19,$29,12 |
stw $20,$29,16 |
stw $31,$29,20 |
add $16,$0,$4 ; command |
add $17,$0,$5 ; start at sector |
add $8,$0,0xc0000000 |
or $18,$8,$6 ; memory address (logicalized) |
add $19,$0,$7 ; number of sectors |
|
; switch over command |
add $8,$0,'r' |
beq $8,$16,dskior ; read |
add $8,$0,'w' |
beq $8,$16,dskiow ; write |
; unknown command |
add $2,$0,1 ; value != 0 signifies error |
j dskiox |
|
; read from disk |
dskior: |
dskior1: ; loop over number of sectors |
beq $19,$0,dskiorsuc ; successful return |
sub $19,$19,1 |
; read a sector |
add $4,$0,'r' |
jal ser1out |
; send sector number |
add $20,$0,32 ; 4 bytes |
dskior2: |
sub $20,$20,8 |
slr $4,$17,$20 |
and $4,$4,0xff |
jal ser1out |
bne $20,$0,dskior2 |
add $17,$17,1 |
; get answer |
jal ser1in |
bne $2,$0,dskiox ; $2 != 0 so we use it as return code |
; read data |
add $20,$0,512 |
dskior3: |
sub $20,$20,1 |
jal ser1in |
stb $2,$18,0 |
add $18,$18,1 |
bne $20,$0,dskior3 |
j dskior1 |
dskiorsuc: |
add $2,$0,$0 |
j dskiox |
|
; write to disk |
dskiow: |
dskiow1: ; loop over number of sectors |
beq $19,$0,dskiowsuc ; successful return |
sub $19,$19,1 |
; write a sector |
add $4,$0,'w' |
jal ser1out |
; send sector number |
add $20,$0,32 ; 4 bytes |
dskiow2: |
sub $20,$20,8 |
slr $4,$17,$20 |
and $4,$4,0xff |
jal ser1out |
bne $20,$0,dskiow2 |
add $17,$17,1 |
; write data |
add $20,$0,512 |
dskiow3: |
sub $20,$20,1 |
ldbu $4,$18,0 |
jal ser1out |
add $18,$18,1 |
bne $20,$0,dskiow3 |
; get answer |
jal ser1in |
bne $2,$0,dskiox |
j dskiow1 |
dskiowsuc: |
add $2,$0,$0 |
dskiox: |
ldw $16,$29,0 |
ldw $17,$29,4 |
ldw $18,$29,8 |
ldw $19,$29,12 |
ldw $20,$29,16 |
ldw $31,$29,20 |
add $29,$29,24 |
jr $31 |
/common/serial.s
0,0 → 1,96
; |
; serial.s -- the serial line interface |
; |
|
;*************************************************************** |
|
.set ser0base,0xF0300000 ; serial line 0 base address |
.set ser1base,0xF0301000 ; serial line 1 base address |
|
.export ser0init ; line 0 initialization |
.export ser0inchk ; line 0 input check |
.export ser0in ; line 0 input |
.export ser0outchk ; line 0 output check |
.export ser0out ; line 0 output |
|
.export ser1init ; line 1 initialization |
.export ser1inchk ; line 1 input check |
.export ser1in ; line 1 input |
.export ser1outchk ; line 1 output check |
.export ser1out ; line 1 output |
|
;*************************************************************** |
|
.code |
.align 4 |
|
ser0init: |
jr $31 |
|
ser0inchk: |
add $8,$0,ser0base |
ldw $2,$8,0 |
and $2,$2,1 |
jr $31 |
|
ser0in: |
add $8,$0,ser0base |
ser0in1: |
ldw $9,$8,0 |
and $9,$9,1 |
beq $9,$0,ser0in1 |
ldw $2,$8,4 |
jr $31 |
|
ser0outchk: |
add $8,$0,ser0base |
ldw $2,$8,8 |
and $2,$2,1 |
jr $31 |
|
ser0out: |
add $8,$0,ser0base |
ser0out1: |
ldw $9,$8,8 |
and $9,$9,1 |
beq $9,$0,ser0out1 |
stw $4,$8,12 |
jr $31 |
|
;*************************************************************** |
|
.code |
.align 4 |
|
ser1init: |
jr $31 |
|
ser1inchk: |
add $8,$0,ser1base |
ldw $2,$8,0 |
and $2,$2,1 |
jr $31 |
|
ser1in: |
add $8,$0,ser1base |
ser1in1: |
ldw $9,$8,0 |
and $9,$9,1 |
beq $9,$0,ser1in1 |
ldw $2,$8,4 |
jr $31 |
|
ser1outchk: |
add $8,$0,ser1base |
ldw $2,$8,8 |
and $2,$2,1 |
jr $31 |
|
ser1out: |
add $8,$0,ser1base |
ser1out1: |
ldw $9,$8,8 |
and $9,$9,1 |
beq $9,$0,ser1out1 |
stw $4,$8,12 |
jr $31 |
/common/serial.h
0,0 → 1,23
/* |
* serial.s -- the serial line interface |
*/ |
|
|
#ifndef _SERIAL_H_ |
#define _SERIAL_H_ |
|
|
void ser0init(void); |
int ser0inchk(void); |
int ser0in(void); |
int ser0outchk(void); |
void ser0out(int c); |
|
void ser1init(void); |
int ser1inchk(void); |
int ser1in(void); |
int ser1outchk(void); |
void ser1out(int c); |
|
|
#endif /* _SERIAL_H_ */ |
/common/mmu.c
0,0 → 1,126
/* |
* mmu.c -- memory and TLB access |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "mmu.h" |
#include "start.h" |
|
|
static Word tlbIndex; |
static Word tlbEntryHi; |
static Word tlbEntryLo; |
static Word badAddress; |
static Word badAccess; |
|
|
Word mmuReadWord(Word vAddr) { |
return *(Word *)vAddr; |
} |
|
|
Half mmuReadHalf(Word vAddr) { |
return *(Half *)vAddr; |
} |
|
|
Byte mmuReadByte(Word vAddr) { |
return *(Byte *)vAddr; |
} |
|
|
void mmuWriteWord(Word vAddr, Word data) { |
*(Word *)vAddr = data; |
} |
|
|
void mmuWriteHalf(Word vAddr, Half data) { |
*(Half *)vAddr = data; |
} |
|
|
void mmuWriteByte(Word vAddr, Byte data) { |
*(Byte *)vAddr = data; |
} |
|
|
Word mmuGetIndex(void) { |
return tlbIndex; |
} |
|
|
void mmuSetIndex(Word value) { |
tlbIndex = value; |
} |
|
|
Word mmuGetEntryHi(void) { |
return tlbEntryHi; |
} |
|
|
void mmuSetEntryHi(Word value) { |
tlbEntryHi = value; |
} |
|
|
Word mmuGetEntryLo(void) { |
return tlbEntryLo; |
} |
|
|
void mmuSetEntryLo(Word value) { |
tlbEntryLo = value; |
} |
|
|
Word mmuGetBadAddr(void) { |
return badAddress; |
} |
|
|
void mmuSetBadAddr(Word value) { |
badAddress = value; |
} |
|
|
Word mmuGetBadAccs(void) { |
return badAccess; |
} |
|
|
void mmuSetBadAccs(Word value) { |
badAccess = value; |
} |
|
|
TLB_Entry mmuGetTLB(int index) { |
Word hi; |
Word lo; |
TLB_Entry result; |
|
hi = getTLB_HI(index); |
lo = getTLB_LO(index); |
result.page = hi & PAGE_MASK; |
result.frame = lo & PAGE_MASK; |
result.write = (lo & TLB_WRITE) ? true : false; |
result.valid = (lo & TLB_VALID) ? true : false; |
return result; |
} |
|
|
void mmuSetTLB(int index, TLB_Entry tlbEntry) { |
Word flags; |
|
flags = 0; |
if (tlbEntry.write) { |
flags |= TLB_WRITE; |
} |
if (tlbEntry.valid) { |
flags |= TLB_VALID; |
} |
setTLB(index, tlbEntry.page, tlbEntry.frame | flags); |
} |
/common/mmu.h
0,0 → 1,56
/* |
* mmu.h -- memory and TLB access |
*/ |
|
|
#ifndef _MMU_H_ |
#define _MMU_H_ |
|
|
#define TLB_SHFT 5 /* log2 of number of TLB entries */ |
#define TLB_SIZE (1 << TLB_SHFT) /* total number of TLB entries */ |
#define TLB_MASK (TLB_SIZE - 1) /* mask for number of TLB entries */ |
#define TLB_FIXED 4 /* number of fixed TLB entries */ |
|
#define TLB_WRITE (1 << 1) /* write bit in EntryLo */ |
#define TLB_VALID (1 << 0) /* valid bit in EntryLo */ |
|
#define MMU_ACCS_MASK 0x07 /* bits used in BadAccs */ |
#define MMU_ACCS_READ 0x00 /* access type = read */ |
#define MMU_ACCS_WRITE 0x04 /* access type = write */ |
#define MMU_ACCS_BYTE 0x00 /* access width = byte */ |
#define MMU_ACCS_HALF 0x01 /* access width = half */ |
#define MMU_ACCS_WORD 0x02 /* access width = word */ |
|
|
typedef struct { |
Word page; /* 20 high-order bits of virtual address */ |
Word frame; /* 20 high-order bits of physical address */ |
Bool write; /* must be true to allow writing to the page */ |
Bool valid; /* must be true for the entry to be valid */ |
} TLB_Entry; |
|
|
Word mmuReadWord(Word vAddr); |
Half mmuReadHalf(Word vAddr); |
Byte mmuReadByte(Word vAddr); |
void mmuWriteWord(Word vAddr, Word data); |
void mmuWriteHalf(Word vAddr, Half data); |
void mmuWriteByte(Word vAddr, Byte data); |
|
Word mmuGetIndex(void); |
void mmuSetIndex(Word value); |
Word mmuGetEntryHi(void); |
void mmuSetEntryHi(Word value); |
Word mmuGetEntryLo(void); |
void mmuSetEntryLo(Word value); |
Word mmuGetBadAddr(void); |
void mmuSetBadAddr(Word value); |
Word mmuGetBadAccs(void); |
void mmuSetBadAccs(Word value); |
|
TLB_Entry mmuGetTLB(int index); |
void mmuSetTLB(int index, TLB_Entry tlbEntry); |
|
|
#endif /* _MMU_H_ */ |
/common/instr.c
0,0 → 1,115
/* |
* instr.c -- instruction encoding |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "instr.h" |
|
|
/* |
* This is the ECO32 machine instruction set. |
* The table below needs no particular order |
* and may have gaps in the instruction encoding. |
*/ |
Instr instrTbl[] = { |
{ "add", FORMAT_RRY, OP_ADD }, |
{ "sub", FORMAT_RRY, OP_SUB }, |
{ "mul", FORMAT_RRY, OP_MUL }, |
{ "mulu", FORMAT_RRX, OP_MULU }, |
{ "div", FORMAT_RRY, OP_DIV }, |
{ "divu", FORMAT_RRX, OP_DIVU }, |
{ "rem", FORMAT_RRY, OP_REM }, |
{ "remu", FORMAT_RRX, OP_REMU }, |
{ "and", FORMAT_RRX, OP_AND }, |
{ "or", FORMAT_RRX, OP_OR }, |
{ "xor", FORMAT_RRX, OP_XOR }, |
{ "xnor", FORMAT_RRX, OP_XNOR }, |
{ "sll", FORMAT_RRX, OP_SLL }, |
{ "slr", FORMAT_RRX, OP_SLR }, |
{ "sar", FORMAT_RRX, OP_SAR }, |
{ "ldhi", FORMAT_RHH, OP_LDHI }, |
{ "beq", FORMAT_RRB, OP_BEQ }, |
{ "bne", FORMAT_RRB, OP_BNE }, |
{ "ble", FORMAT_RRB, OP_BLE }, |
{ "bleu", FORMAT_RRB, OP_BLEU }, |
{ "blt", FORMAT_RRB, OP_BLT }, |
{ "bltu", FORMAT_RRB, OP_BLTU }, |
{ "bge", FORMAT_RRB, OP_BGE }, |
{ "bgeu", FORMAT_RRB, OP_BGEU }, |
{ "bgt", FORMAT_RRB, OP_BGT }, |
{ "bgtu", FORMAT_RRB, OP_BGTU }, |
{ "j", FORMAT_J, OP_J }, |
{ "jr", FORMAT_JR, OP_JR }, |
{ "jal", FORMAT_J, OP_JAL }, |
{ "jalr", FORMAT_JR, OP_JALR }, |
{ "trap", FORMAT_N, OP_TRAP }, |
{ "rfx", FORMAT_N, OP_RFX }, |
{ "ldw", FORMAT_RRS, OP_LDW }, |
{ "ldh", FORMAT_RRS, OP_LDH }, |
{ "ldhu", FORMAT_RRS, OP_LDHU }, |
{ "ldb", FORMAT_RRS, OP_LDB }, |
{ "ldbu", FORMAT_RRS, OP_LDBU }, |
{ "stw", FORMAT_RRS, OP_STW }, |
{ "sth", FORMAT_RRS, OP_STH }, |
{ "stb", FORMAT_RRS, OP_STB }, |
{ "mvfs", FORMAT_RH, OP_MVFS }, |
{ "mvts", FORMAT_RH, OP_MVTS }, |
{ "tbs", FORMAT_N, OP_TBS }, |
{ "tbwr", FORMAT_N, OP_TBWR }, |
{ "tbri", FORMAT_N, OP_TBRI }, |
{ "tbwi", FORMAT_N, OP_TBWI } |
}; |
|
|
Instr *instrCodeTbl[64]; |
|
|
static int instrCompare(const void *instr1, const void *instr2) { |
return strcmp(((Instr *) instr1)->name, ((Instr *) instr2)->name); |
} |
|
|
void initInstrTable(void) { |
int i; |
|
/* first sort instruction table alphabetically */ |
qsort(instrTbl, sizeof(instrTbl)/sizeof(instrTbl[0]), |
sizeof(instrTbl[0]), instrCompare); |
/* then initialize instruction code table */ |
for (i = 0; i < 64; i++) { |
instrCodeTbl[i] = NULL; |
} |
for (i = 0; i < sizeof(instrTbl)/sizeof(instrTbl[0]); i++) { |
instrCodeTbl[instrTbl[i].opcode] = &instrTbl[i]; |
if (instrTbl[i].format == FORMAT_RRX || |
instrTbl[i].format == FORMAT_RRY) { |
/* enter the immediate variant of this instruction also */ |
instrCodeTbl[instrTbl[i].opcode + 1] = &instrTbl[i]; |
} |
} |
} |
|
|
Instr *lookupInstr(char *name) { |
int lo, hi, tst; |
int res; |
|
lo = 0; |
hi = sizeof(instrTbl) / sizeof(instrTbl[0]) - 1; |
while (lo <= hi) { |
tst = (lo + hi) / 2; |
res = strcmp(instrTbl[tst].name, name); |
if (res == 0) { |
return &instrTbl[tst]; |
} |
if (res < 0) { |
lo = tst + 1; |
} else { |
hi = tst - 1; |
} |
} |
return NULL; |
} |
/common/instr.h
0,0 → 1,125
/* |
* instr.h -- instruction encoding |
*/ |
|
|
#ifndef _INSTR_H_ |
#define _INSTR_H_ |
|
|
#define FORMAT_N 0 /* no operands */ |
#define FORMAT_RH 1 /* one register and a half operand */ |
#define FORMAT_RHH 2 /* one register and a half operand */ |
/* ATTENTION: high-order 16 bits encoded */ |
#define FORMAT_RRH 3 /* two registers and a half operand */ |
#define FORMAT_RRS 4 /* two registers and a signed half operand */ |
#define FORMAT_RRR 5 /* three register operands */ |
#define FORMAT_RRX 6 /* either FORMAT_RRR or FORMAT_RRH */ |
#define FORMAT_RRY 7 /* either FORMAT_RRR or FORMAT_RRS */ |
#define FORMAT_RRB 8 /* two registers and a 16 bit signed |
offset operand */ |
#define FORMAT_J 9 /* no registers and a 26 bit signed |
offset operand */ |
#define FORMAT_JR 10 /* one register operand */ |
|
|
#define MASK(n) ((((Word) 1) << n) - 1) |
#define SIGN(n) (((Word) 1) << (n - 1)) |
#define ZEXT16(x) (((Word) (x)) & MASK(16)) |
#define SEXT16(x) (((Word) (x)) & SIGN(16) ? \ |
(((Word) (x)) | ~MASK(16)) : \ |
(((Word) (x)) & MASK(16))) |
#define SEXT26(x) (((Word) (x)) & SIGN(26) ? \ |
(((Word) (x)) | ~MASK(26)) : \ |
(((Word) (x)) & MASK(26))) |
|
|
#define OP_ADD 0x00 |
#define OP_ADDI 0x01 |
#define OP_SUB 0x02 |
#define OP_SUBI 0x03 |
|
#define OP_MUL 0x04 |
#define OP_MULI 0x05 |
#define OP_MULU 0x06 |
#define OP_MULUI 0x07 |
#define OP_DIV 0x08 |
#define OP_DIVI 0x09 |
#define OP_DIVU 0x0A |
#define OP_DIVUI 0x0B |
#define OP_REM 0x0C |
#define OP_REMI 0x0D |
#define OP_REMU 0x0E |
#define OP_REMUI 0x0F |
|
#define OP_AND 0x10 |
#define OP_ANDI 0x11 |
#define OP_OR 0x12 |
#define OP_ORI 0x13 |
#define OP_XOR 0x14 |
#define OP_XORI 0x15 |
#define OP_XNOR 0x16 |
#define OP_XNORI 0x17 |
|
#define OP_SLL 0x18 |
#define OP_SLLI 0x19 |
#define OP_SLR 0x1A |
#define OP_SLRI 0x1B |
#define OP_SAR 0x1C |
#define OP_SARI 0x1D |
|
#define OP_LDHI 0x1F |
|
#define OP_BEQ 0x20 |
#define OP_BNE 0x21 |
#define OP_BLE 0x22 |
#define OP_BLEU 0x23 |
#define OP_BLT 0x24 |
#define OP_BLTU 0x25 |
#define OP_BGE 0x26 |
#define OP_BGEU 0x27 |
#define OP_BGT 0x28 |
#define OP_BGTU 0x29 |
|
#define OP_J 0x2A |
#define OP_JR 0x2B |
#define OP_JAL 0x2C |
#define OP_JALR 0x2D |
|
#define OP_TRAP 0x2E |
#define OP_RFX 0x2F |
|
#define OP_LDW 0x30 |
#define OP_LDH 0x31 |
#define OP_LDHU 0x32 |
#define OP_LDB 0x33 |
#define OP_LDBU 0x34 |
|
#define OP_STW 0x35 |
#define OP_STH 0x36 |
#define OP_STB 0x37 |
|
#define OP_MVFS 0x38 |
#define OP_MVTS 0x39 |
#define OP_TBS 0x3A |
#define OP_TBWR 0x3B |
#define OP_TBRI 0x3C |
#define OP_TBWI 0x3D |
|
|
typedef struct { |
char *name; |
int format; |
Byte opcode; |
} Instr; |
|
|
extern Instr instrTbl[]; |
extern Instr *instrCodeTbl[]; |
|
|
void initInstrTable(void); |
Instr *lookupInstr(char *name); |
|
|
#endif /* _INSTR_H_ */ |
/common/disasm.c
0,0 → 1,138
/* |
* disasm.c -- disassembler |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "instr.h" |
#include "disasm.h" |
|
|
static char instrBuffer[100]; |
|
|
static void disasmN(char *opName, Word immed) { |
if (immed == 0) { |
sprintf(instrBuffer, "%-7s", opName); |
} else { |
sprintf(instrBuffer, "%-7s %08X", opName, immed); |
} |
} |
|
|
static void disasmRH(char *opName, int r1, Half immed) { |
sprintf(instrBuffer, "%-7s $%d,%04X", opName, r1, immed); |
} |
|
|
static void disasmRHH(char *opName, int r1, Half immed) { |
sprintf(instrBuffer, "%-7s $%d,%08X", opName, r1, (Word) immed << 16); |
} |
|
|
static void disasmRRH(char *opName, int r1, int r2, Half immed) { |
sprintf(instrBuffer, "%-7s $%d,$%d,%04X", opName, r1, r2, immed); |
} |
|
|
static void disasmRRS(char *opName, int r1, int r2, Half immed) { |
sprintf(instrBuffer, "%-7s $%d,$%d,%s%04X", opName, r1, r2, |
SIGN(16) & immed ? "-" : "+", |
SIGN(16) & immed ? -(signed)SEXT16(immed) : SEXT16(immed)); |
} |
|
|
static void disasmRRR(char *opName, int r1, int r2, int r3) { |
sprintf(instrBuffer, "%-7s $%d,$%d,$%d", opName, r1, r2, r3); |
} |
|
|
static void disasmRRB(char *opName, int r1, int r2, Half offset, Word locus) { |
sprintf(instrBuffer, "%-7s $%d,$%d,%08X", opName, |
r1, r2, (locus + 4) + (SEXT16(offset) << 2)); |
} |
|
|
static void disasmJ(char *opName, Word offset, Word locus) { |
sprintf(instrBuffer, "%-7s %08X", opName, |
(locus + 4) + (SEXT26(offset) << 2)); |
} |
|
|
static void disasmJR(char *opName, int r1) { |
sprintf(instrBuffer, "%-7s $%d", opName, r1); |
} |
|
|
char *disasm(Word instr, Word locus) { |
Byte opcode; |
Instr *ip; |
|
opcode = (instr >> 26) & 0x3F; |
ip = instrCodeTbl[opcode]; |
if (ip == NULL) { |
disasmN("???", 0); |
} else { |
switch (ip->format) { |
case FORMAT_N: |
disasmN(ip->name, instr & 0x03FFFFFF); |
break; |
case FORMAT_RH: |
disasmRH(ip->name, (instr >> 16) & 0x1F, instr & 0x0000FFFF); |
break; |
case FORMAT_RHH: |
disasmRHH(ip->name, (instr >> 16) & 0x1F, instr & 0x0000FFFF); |
break; |
case FORMAT_RRH: |
disasmRRH(ip->name, (instr >> 16) & 0x1F, |
(instr >> 21) & 0x1F, instr & 0x0000FFFF); |
break; |
case FORMAT_RRS: |
disasmRRS(ip->name, (instr >> 16) & 0x1F, |
(instr >> 21) & 0x1F, instr & 0x0000FFFF); |
break; |
case FORMAT_RRR: |
disasmRRR(ip->name, (instr >> 11) & 0x1F, |
(instr >> 21) & 0x1F, (instr >> 16) & 0x1F); |
break; |
case FORMAT_RRX: |
if ((opcode & 1) == 0) { |
/* the FORMAT_RRR variant */ |
disasmRRR(ip->name, (instr >> 11) & 0x1F, |
(instr >> 21) & 0x1F, (instr >> 16) & 0x1F); |
} else { |
/* the FORMAT_RRH variant */ |
disasmRRH(ip->name, (instr >> 16) & 0x1F, |
(instr >> 21) & 0x1F, instr & 0x0000FFFF); |
} |
break; |
case FORMAT_RRY: |
if ((opcode & 1) == 0) { |
/* the FORMAT_RRR variant */ |
disasmRRR(ip->name, (instr >> 11) & 0x1F, |
(instr >> 21) & 0x1F, (instr >> 16) & 0x1F); |
} else { |
/* the FORMAT_RRS variant */ |
disasmRRS(ip->name, (instr >> 16) & 0x1F, |
(instr >> 21) & 0x1F, instr & 0x0000FFFF); |
} |
break; |
case FORMAT_RRB: |
disasmRRB(ip->name, (instr >> 21) & 0x1F, |
(instr >> 16) & 0x1F, instr & 0x0000FFFF, locus); |
break; |
case FORMAT_J: |
disasmJ(ip->name, instr & 0x03FFFFFF, locus); |
break; |
case FORMAT_JR: |
disasmJR(ip->name, (instr >> 21) & 0x1F); |
break; |
default: |
printf("illegal entry in instruction table\n"); |
break; |
} |
} |
return instrBuffer; |
} |
/common/asm.c
0,0 → 1,370
/* |
* asm.c -- assembler |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "instr.h" |
#include "asm.h" |
|
|
#define MAX_TOKENS 10 |
|
|
static char *msgs[] = { |
/* 0 */ "too many tokens on line", |
/* 1 */ "empty line", |
/* 2 */ "unknown instruction name", |
/* 3 */ "unknown instruction format", |
/* 4 */ "excess tokens on line", |
/* 5 */ "too few operands", |
/* 6 */ "illegal register", |
/* 7 */ "illegal immediate value", |
/* 8 */ "immediate value out of range", |
/* 9 */ "target is not aligned", |
/* 10 */ "target cannot be reached" |
}; |
|
|
static Bool asmReg(char *token, int *reg) { |
char *end; |
|
if (*token != '$') { |
return false; |
} |
*reg = strtoul(token + 1, &end, 10); |
if (*end != '\0') { |
return false; |
} |
if (*reg < 0 || *reg >= 32) { |
return false; |
} |
return true; |
} |
|
|
static Bool asmNum(char *token, unsigned int *val) { |
char *end; |
|
*val = strtoul(token, &end, 16); |
return *end == '\0'; |
} |
|
|
char *asmInstr(char *line, Word addr, Word *instrPtr) { |
char *tokens[MAX_TOKENS]; |
int n; |
char *p; |
Instr *instr; |
Word result; |
int r1, r2, r3; |
unsigned int uimm; |
signed int simm; |
|
/* separate tokens */ |
n = 0; |
p = strtok(line, " \t\n,"); |
while (p != NULL) { |
if (n == MAX_TOKENS) { |
return msgs[0]; |
} |
tokens[n++] = p; |
p = strtok(NULL, " \t\n,"); |
} |
if (n == 0) { |
return msgs[1]; |
} |
/* lookup mnemonic */ |
instr = lookupInstr(tokens[0]); |
if (instr == NULL) { |
return msgs[2]; |
} |
/* do processing according to format */ |
switch (instr->format) { |
case FORMAT_N: |
/* no operands (but may get a constant operand) */ |
if (n > 2) { |
return msgs[4]; |
} |
if (n < 1) { |
return msgs[5]; |
} |
if (n == 2) { |
if (!asmNum(tokens[1], &uimm)) { |
return msgs[7]; |
} |
} else { |
uimm = 0; |
} |
result = ((Word) instr->opcode << 26) | |
(uimm & MASK(26)); |
break; |
case FORMAT_RH: |
/* one register and a half operand */ |
if (n > 3) { |
return msgs[4]; |
} |
if (n < 3) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
if (!asmNum(tokens[2], &uimm)) { |
return msgs[7]; |
} |
if (uimm >= (unsigned) (1 << 16)) { |
return msgs[8]; |
} |
result = ((Word) instr->opcode << 26) | |
(r1 << 16) | |
(uimm & MASK(16)); |
break; |
case FORMAT_RHH: |
/* one register and a half operand */ |
/* ATTENTION: high-order 16 bits encoded */ |
if (n > 3) { |
return msgs[4]; |
} |
if (n < 3) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
if (!asmNum(tokens[2], &uimm)) { |
return msgs[7]; |
} |
uimm >>= 16; |
if (uimm >= (unsigned) (1 << 16)) { |
return msgs[8]; |
} |
result = ((Word) instr->opcode << 26) | |
(r1 << 16) | |
(uimm & MASK(16)); |
break; |
case FORMAT_RRH: |
/* two registers and a half operand */ |
if (n > 4) { |
return msgs[4]; |
} |
if (n < 4) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
if (!asmReg(tokens[2], &r2)) { |
return msgs[6]; |
} |
if (!asmNum(tokens[3], &uimm)) { |
return msgs[7]; |
} |
if (uimm >= (unsigned) (1 << 16)) { |
return msgs[8]; |
} |
result = ((Word) instr->opcode << 26) | |
(r2 << 21) | |
(r1 << 16) | |
(uimm & MASK(16)); |
break; |
case FORMAT_RRS: |
/* two registers and a signed half operand */ |
if (n > 4) { |
return msgs[4]; |
} |
if (n < 4) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
if (!asmReg(tokens[2], &r2)) { |
return msgs[6]; |
} |
if (!asmNum(tokens[3], (unsigned int *) &simm)) { |
return msgs[7]; |
} |
if (simm >= (signed) (1 << 15) || |
simm < - (signed) (1 << 15)) { |
return msgs[8]; |
} |
result = ((Word) instr->opcode << 26) | |
(r2 << 21) | |
(r1 << 16) | |
(simm & MASK(16)); |
break; |
case FORMAT_RRR: |
/* three register operands */ |
if (n > 4) { |
return msgs[4]; |
} |
if (n < 4) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
if (!asmReg(tokens[2], &r2)) { |
return msgs[6]; |
} |
if (!asmReg(tokens[3], &r3)) { |
return msgs[6]; |
} |
result = ((Word) instr->opcode << 26) | |
(r2 << 21) | |
(r3 << 16) | |
(r1 << 11); |
break; |
case FORMAT_RRX: |
/* either FORMAT_RRR or FORMAT_RRH */ |
if (n > 4) { |
return msgs[4]; |
} |
if (n < 4) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
if (!asmReg(tokens[2], &r2)) { |
return msgs[6]; |
} |
if (*tokens[3] == '$') { |
/* FORMAT_RRR */ |
if (!asmReg(tokens[3], &r3)) { |
return msgs[6]; |
} |
result = ((Word) instr->opcode << 26) | |
(r2 << 21) | |
(r3 << 16) | |
(r1 << 11); |
} else { |
/* FORMAT_RRH */ |
if (!asmNum(tokens[3], &uimm)) { |
return msgs[7]; |
} |
if (uimm >= (unsigned) (1 << 16)) { |
return msgs[8]; |
} |
result = (((Word) instr->opcode + 1) << 26) | |
(r2 << 21) | |
(r1 << 16) | |
(uimm & MASK(16)); |
} |
break; |
case FORMAT_RRY: |
/* either FORMAT_RRR or FORMAT_RRS */ |
if (n > 4) { |
return msgs[4]; |
} |
if (n < 4) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
if (!asmReg(tokens[2], &r2)) { |
return msgs[6]; |
} |
if (*tokens[3] == '$') { |
/* FORMAT_RRR */ |
if (!asmReg(tokens[3], &r3)) { |
return msgs[6]; |
} |
result = ((Word) instr->opcode << 26) | |
(r2 << 21) | |
(r3 << 16) | |
(r1 << 11); |
} else { |
/* FORMAT_RRS */ |
if (!asmNum(tokens[3], (unsigned int *) &simm)) { |
return msgs[7]; |
} |
if (simm >= (signed) (1 << 15) || |
simm < - (signed) (1 << 15)) { |
return msgs[8]; |
} |
result = (((Word) instr->opcode + 1) << 26) | |
(r2 << 21) | |
(r1 << 16) | |
(simm & MASK(16)); |
} |
break; |
case FORMAT_RRB: |
/* two registers and a 16 bit signed offset operand */ |
if (n > 4) { |
return msgs[4]; |
} |
if (n < 4) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
if (!asmReg(tokens[2], &r2)) { |
return msgs[6]; |
} |
if (!asmNum(tokens[3], (unsigned int *) &simm)) { |
return msgs[7]; |
} |
if ((simm & 0x00000003) != 0) { |
return msgs[9]; |
} |
simm -= addr + 4; |
simm /= 4; |
if (simm >= (signed) (1 << 15) || |
simm < - (signed) (1 << 15)) { |
return msgs[10]; |
} |
result = ((Word) instr->opcode << 26) | |
(r1 << 21) | |
(r2 << 16) | |
(simm & MASK(16)); |
break; |
case FORMAT_J: |
/* no registers and a 26 bit signed offset operand */ |
if (n > 2) { |
return msgs[4]; |
} |
if (n < 2) { |
return msgs[5]; |
} |
if (!asmNum(tokens[1], (unsigned int *) &simm)) { |
return msgs[7]; |
} |
if ((simm & 0x00000003) != 0) { |
return msgs[9]; |
} |
simm -= addr + 4; |
simm /= 4; |
if (simm >= (signed) (1 << 25) || |
simm < - (signed) (1 << 25)) { |
return msgs[10]; |
} |
result = ((Word) instr->opcode << 26) | |
(simm & MASK(26)); |
break; |
case FORMAT_JR: |
/* one register operand */ |
if (n > 2) { |
return msgs[4]; |
} |
if (n < 2) { |
return msgs[5]; |
} |
if (!asmReg(tokens[1], &r1)) { |
return msgs[6]; |
} |
result = ((Word) instr->opcode << 26) | |
(r1 << 21); |
break; |
default: |
return msgs[3]; |
} |
/* line successfully assembled */ |
*instrPtr = result; |
return NULL; |
} |
/common/keyboard.s
0,0 → 1,149
; |
; keyboard.s -- a PC keyboard as input device |
; |
|
;*************************************************************** |
|
.set kbdbase,0xF0200000 ; keyboard base address |
|
; .import cout |
; .import byteout |
|
.import xltbl1 ; kbd translation table 1 |
.import xltbl2 ; kbd translation table 2 |
|
.export kbdinit ; initialize keyboard |
.export kbdinchk ; check if input available |
.export kbdin ; do keyboard input |
|
;*************************************************************** |
|
.code |
.align 4 |
|
kbdinit: |
jr $31 |
|
kbdinchk: |
add $8,$0,kbdbase |
ldw $2,$8,0 |
and $2,$2,1 |
jr $31 |
|
kbdin: |
sub $29,$29,12 |
stw $31,$29,8 |
stw $16,$29,4 |
stw $17,$29,0 |
kbdin0: |
jal kbdinp |
add $16,$2,$0 ; key 1 in $16 |
add $8,$0,0xF0 |
bne $16,$8,kbdin2 |
kbdin1: |
jal kbdinp |
j kbdin0 |
kbdin2: |
jal kbdinp |
add $17,$2,$0 ; key 2 in $17 |
beq $17,$16,kbdin2 |
add $8,$0,0xF0 |
beq $17,$8,kbdin3 |
j kbdin5 |
kbdin3: |
jal kbdinp |
bne $2,$16,kbdin2 |
kbdin4: |
add $4,$16,$0 ; use key 1 |
add $5,$0,xltbl1 ; with translation table 1 |
jal xlat |
j kbdx |
kbdin5: |
jal kbdinp |
add $8,$0,0xF0 |
bne $2,$8,kbdin5 |
kbdin6: |
jal kbdinp |
beq $2,$16,kbdin7 |
beq $2,$17,kbdin9 |
j kbdin5 |
kbdin7: |
jal kbdinp |
add $8,$0,0xF0 |
bne $2,$8,kbdin7 |
kbdin8: |
jal kbdinp |
bne $2,$17,kbdin7 |
j kbdin11 |
kbdin9: |
jal kbdinp |
add $8,$0,0xF0 |
bne $2,$8,kbdin9 |
kbdin10: |
jal kbdinp |
bne $2,$16,kbdin9 |
j kbdin11 |
kbdin11: |
add $8,$0,0x12 ; left shift key |
beq $16,$8,kbdin12 |
add $8,$0,0x59 ; right shift key |
beq $16,$8,kbdin12 |
add $8,$0,0x14 ; ctrl key |
beq $16,$8,kbdin14 |
j kbdin13 |
kbdin12: |
add $4,$17,$0 ; use key 2 |
add $5,$0,xltbl2 ; with translation table 2 |
jal xlat |
j kbdx |
kbdin13: |
add $4,$16,$0 ; use key 1 |
add $5,$0,xltbl1 ; with translation table 1 |
jal xlat |
j kbdx |
kbdin14: |
add $4,$17,$0 ; use key 2 |
add $5,$0,xltbl1 ; with translation table 1 |
jal xlat |
and $2,$2,0xFF-0x60 ; then reset bits 0x60 |
j kbdx |
kbdx: |
ldw $17,$29,0 |
ldw $16,$29,4 |
ldw $31,$29,8 |
add $29,$29,12 |
jr $31 |
|
kbdinp: |
add $8,$0,kbdbase |
kbdinp1: |
ldw $9,$8,0 |
and $9,$9,1 |
beq $9,$0,kbdinp1 ; wait until character ready |
ldw $2,$8,4 ; get character |
add $9,$0,0xE0 |
beq $2,$9,kbdinp1 ; ignore E0 prefix |
add $9,$0,0xE1 |
beq $2,$9,kbdinp1 ; as well as E1 prefix |
jr $31 |
|
xlat: |
sub $29,$29,8 |
stw $31,$29,4 |
stw $16,$29,0 |
and $16,$4,0xFF |
add $8,$16,$5 |
ldbu $2,$8,0 |
bne $2,$0,xlat1 |
; add $4,$0,'<' |
; jal cout |
; add $4,$16,$0 |
; jal byteout |
; add $4,$0,'>' |
; jal cout |
add $2,$16,$0 |
xlat1: |
ldw $16,$29,0 |
ldw $31,$29,4 |
add $29,$29,8 |
jr $31 |
/common/command.h
0,0 → 1,13
/* |
* command.h -- command interpreter |
*/ |
|
|
#ifndef _COMMAND_H_ |
#define _COMMAND_H_ |
|
|
void execCommand(char *line); |
|
|
#endif /* _COMMAND_H_ */ |
/common/romlib.c
0,0 → 1,636
/* |
* romlib.c -- the ROM library |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "start.h" |
|
|
/**************************************************************/ |
|
|
/* |
* This is only for debugging. |
* Place a breakpoint at the very beginning of this routine |
* and call it wherever you want to break execution. |
*/ |
void debugBreak(void) { |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Count the length of a string (without terminating null character). |
*/ |
int strlen(const char *s) { |
const char *p; |
|
p = s; |
while (*p != '\0') { |
p++; |
} |
return p - s; |
} |
|
|
/* |
* Compare two strings. |
* Return a number < 0, = 0, or > 0 iff the first string is less |
* than, equal to, or greater than the second one, respectively. |
*/ |
int strcmp(const char *s, const char *t) { |
while (*s == *t) { |
if (*s == '\0') { |
return 0; |
} |
s++; |
t++; |
} |
return *s - *t; |
} |
|
|
/* |
* Copy string t to string s (includes terminating null character). |
*/ |
char *strcpy(char *s, const char *t) { |
char *p; |
|
p = s; |
while ((*p = *t) != '\0') { |
p++; |
t++; |
} |
return s; |
} |
|
|
/* |
* Append string t to string s. |
*/ |
char *strcat(char *s, const char *t) { |
char *p; |
|
p = s; |
while (*p != '\0') { |
p++; |
} |
while ((*p = *t) != '\0') { |
p++; |
t++; |
} |
return s; |
} |
|
|
/* |
* Locate character c in string s. |
*/ |
char *strchr(const char *s, char c) { |
while (*s != c) { |
if (*s == '\0') { |
return NULL; |
} |
s++; |
} |
return (char *) s; |
} |
|
|
/* |
* Extract the next token from the string s, delimited |
* by any character from the delimiter string t. |
*/ |
char *strtok(char *s, const char *t) { |
static char *p; |
char *q; |
|
if (s != NULL) { |
p = s; |
} else { |
p++; |
} |
while (*p != '\0' && strchr(t, *p) != NULL) { |
p++; |
} |
if (*p == '\0') { |
return NULL; |
} |
q = p++; |
while (*p != '\0' && strchr(t, *p) == NULL) { |
p++; |
} |
if (*p != '\0') { |
*p = '\0'; |
} else { |
p--; |
} |
return q; |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Determine if a character is 'white space'. |
*/ |
static Bool isspace(char c) { |
Bool res; |
|
switch (c) { |
case ' ': |
case '\f': |
case '\n': |
case '\r': |
case '\t': |
case '\v': |
res = true; |
break; |
default: |
res = false; |
break; |
} |
return res; |
} |
|
|
/* |
* Check for valid digit, and convert to value. |
*/ |
static Bool checkDigit(char c, int base, int *value) { |
if (c >= '0' && c <= '9') { |
*value = c - '0'; |
} else |
if (c >= 'A' && c <= 'Z') { |
*value = c - 'A' + 10; |
} else |
if (c >= 'a' && c <= 'z') { |
*value = c - 'a' + 10; |
} else { |
return false; |
} |
return *value < base; |
} |
|
|
/* |
* Convert initial part of string to unsigned long integer. |
*/ |
unsigned long strtoul(const char *s, char **endp, int base) { |
unsigned long res; |
int sign; |
int digit; |
|
res = 0; |
while (isspace(*s)) { |
s++; |
} |
if (*s == '+') { |
sign = 1; |
s++; |
} else |
if (*s == '-') { |
sign = -1; |
s++; |
} else { |
sign = 1; |
} |
if (base == 0 || base == 16) { |
if (*s == '0' && |
(*(s + 1) == 'x' || *(s + 1) == 'X')) { |
/* base is 16 */ |
s += 2; |
base = 16; |
} else { |
/* base is 0 or 16, but number does not start with "0x" */ |
if (base == 0) { |
if (*s == '0') { |
s++; |
base = 8; |
} else { |
base = 10; |
} |
} else { |
/* take base as is */ |
} |
} |
} else { |
/* take base as is */ |
} |
while (checkDigit(*s, base, &digit)) { |
res *= base; |
res += digit; |
s++; |
} |
if (endp != NULL) { |
*endp = (char *) s; |
} |
return sign * res; |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Exchange two array items of a given size. |
*/ |
static void xchg(char *p, char *q, int size) { |
char t; |
|
while (size--) { |
t = *p; |
*p++ = *q; |
*q++ = t; |
} |
} |
|
|
/* |
* This is a recursive version of quicksort. |
*/ |
static void sort(char *l, char *r, int size, |
int (*cmp)(const void *, const void *)) { |
char *i; |
char *j; |
char *x; |
|
i = l; |
j = r; |
x = l + (((r - l) / size) / 2) * size; |
do { |
while (cmp(i, x) < 0) { |
i += size; |
} |
while (cmp(x, j) < 0) { |
j -= size; |
} |
if (i <= j) { |
/* exchange array elements i and j */ |
/* attention: update x if it is one of these */ |
if (x == i) { |
x = j; |
} else |
if (x == j) { |
x = i; |
} |
xchg(i, j, size); |
i += size; |
j -= size; |
} |
} while (i <= j); |
if (l < j) { |
sort(l, j, size, cmp); |
} |
if (i < r) { |
sort(i, r, size, cmp); |
} |
} |
|
|
/* |
* External interface for the quicksort algorithm. |
*/ |
void qsort(void *base, int n, int size, |
int (*cmp)(const void *, const void*)) { |
sort((char *) base, (char *) base + (n - 1) * size, size, cmp); |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Input a character from the console. |
*/ |
char getchar(void) { |
return cin(); |
} |
|
|
/* |
* Output a character on the console. |
* Replace LF by CR/LF. |
*/ |
void putchar(char c) { |
if (c == '\n') { |
cout('\r'); |
} |
cout(c); |
} |
|
|
/* |
* Output a string on the console. |
* Replace LF by CR/LF. |
*/ |
void puts(const char *s) { |
while (*s != '\0') { |
putchar(*s); |
s++; |
} |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Count the number of characters needed to represent |
* a given number in base 10. |
*/ |
static int countPrintn(long n) { |
long a; |
int res; |
|
res = 0; |
if (n < 0) { |
res++; |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
res += countPrintn(a); |
} |
return res + 1; |
} |
|
|
/* |
* Output a number in base 10. |
*/ |
static void *printn(void *(*emit)(void *, char), void *arg, |
int *nchar, long n) { |
long a; |
|
if (n < 0) { |
arg = emit(arg, '-'); |
(*nchar)++; |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
arg = printn(emit, arg, nchar, a); |
} |
arg = emit(arg, n % 10 + '0'); |
(*nchar)++; |
return arg; |
} |
|
|
/* |
* Count the number of characters needed to represent |
* a given number in a given base. |
*/ |
static int countPrintu(unsigned long n, unsigned long b) { |
unsigned long a; |
int res; |
|
res = 0; |
a = n / b; |
if (a != 0) { |
res += countPrintu(a, b); |
} |
return res + 1; |
} |
|
|
/* |
* Output a number in a given base. |
*/ |
static void *printu(void *(*emit)(void *, char), void *arg, |
int *nchar, unsigned long n, unsigned long b, |
Bool upperCase) { |
unsigned long a; |
|
a = n / b; |
if (a != 0) { |
arg = printu(emit, arg, nchar, a, b, upperCase); |
} |
if (upperCase) { |
arg = emit(arg, "0123456789ABCDEF"[n % b]); |
(*nchar)++; |
} else { |
arg = emit(arg, "0123456789abcdef"[n % b]); |
(*nchar)++; |
} |
return arg; |
} |
|
|
/* |
* Output a number of filler characters. |
*/ |
static void *fill(void *(*emit)(void *, char), void *arg, |
int *nchar, int numFillers, char filler) { |
while (numFillers-- > 0) { |
arg = emit(arg, filler); |
(*nchar)++; |
} |
return arg; |
} |
|
|
/* |
* This function does the real work of formatted printing. |
*/ |
static int doPrintf(void *(*emit)(void *, char), void *arg, |
const char *fmt, va_list ap) { |
int nchar; |
char c; |
int n; |
long ln; |
unsigned int u; |
unsigned long lu; |
char *s; |
Bool negFlag; |
char filler; |
int width, count; |
|
nchar = 0; |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
return nchar; |
} |
arg = emit(arg, c); |
nchar++; |
} |
c = *fmt++; |
if (c == '-') { |
negFlag = true; |
c = *fmt++; |
} else { |
negFlag = false; |
} |
if (c == '0') { |
filler = '0'; |
c = *fmt++; |
} else { |
filler = ' '; |
} |
width = 0; |
while (c >= '0' && c <= '9') { |
width *= 10; |
width += c - '0'; |
c = *fmt++; |
} |
if (c == 'd') { |
n = va_arg(ap, int); |
count = countPrintn(n); |
if (width > 0 && !negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
arg = printn(emit, arg, &nchar, n); |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
} else |
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') { |
u = va_arg(ap, int); |
count = countPrintu(u, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10)); |
if (width > 0 && !negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
arg = printu(emit, arg, &nchar, u, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10), |
c == 'X'); |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
} else |
if (c == 'l') { |
c = *fmt++; |
if (c == 'd') { |
ln = va_arg(ap, long); |
count = countPrintn(ln); |
if (width > 0 && !negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
arg = printn(emit, arg, &nchar, ln); |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
} else |
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') { |
lu = va_arg(ap, long); |
count = countPrintu(lu, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10)); |
if (width > 0 && !negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
arg = printu(emit, arg, &nchar, lu, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10), |
c == 'X'); |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
} else { |
arg = emit(arg, 'l'); |
nchar++; |
arg = emit(arg, c); |
nchar++; |
} |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
count = strlen(s); |
if (width > 0 && !negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
while ((c = *s++) != '\0') { |
arg = emit(arg, c); |
nchar++; |
} |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
} else |
if (c == 'c') { |
c = va_arg(ap, char); |
arg = emit(arg, c); |
nchar++; |
} else { |
arg = emit(arg, c); |
nchar++; |
} |
} |
/* never reached */ |
return 0; |
} |
|
|
/* |
* Emit a character to the console. |
*/ |
static void *emitToConsole(void *dummy, char c) { |
putchar(c); |
return dummy; |
} |
|
|
/* |
* Formatted output with a variable argument list. |
*/ |
int vprintf(const char *fmt, va_list ap) { |
int n; |
|
n = doPrintf(emitToConsole, NULL, fmt, ap); |
return n; |
} |
|
|
/* |
* Formatted output. |
*/ |
int printf(const char *fmt, ...) { |
int n; |
va_list ap; |
|
va_start(ap, fmt); |
n = vprintf(fmt, ap); |
va_end(ap); |
return n; |
} |
|
|
/* |
* Emit a character to a buffer. |
*/ |
static void *emitToBuffer(void *bufptr, char c) { |
*(char *)bufptr = c; |
return (char *) bufptr + 1; |
} |
|
|
/* |
* Formatted output into a buffer with a variable argument list. |
*/ |
int vsprintf(char *s, const char *fmt, va_list ap) { |
int n; |
|
n = doPrintf(emitToBuffer, s, fmt, ap); |
s[n] = '\0'; |
return n; |
} |
|
|
/* |
* Formatted output into a buffer. |
*/ |
int sprintf(char *s, const char *fmt, ...) { |
int n; |
va_list ap; |
|
va_start(ap, fmt); |
n = vsprintf(s, fmt, ap); |
va_end(ap); |
return n; |
} |
/common/display.s
0,0 → 1,225
; |
; display.s -- a memory-mapped alphanumerical display |
; |
|
;*************************************************************** |
|
.set dspbase,0xF0100000 ; display base address |
|
.export dspinit ; initialize display |
.export dspoutchk ; check for output possible |
.export dspout ; do display output |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; initialize display |
dspinit: |
sub $29,$29,4 |
stw $31,$29,0 |
jal clrscr |
add $8,$0,scrrow |
stw $0,$8,0 |
add $8,$0,scrcol |
stw $0,$8,0 |
jal calcp |
jal stcrs |
ldw $31,$29,0 |
add $29,$29,4 |
jr $31 |
|
; check if a character can be written |
dspoutchk: |
add $2,$0,1 |
jr $31 |
|
; output a character on the display |
dspout: |
sub $29,$29,8 |
stw $31,$29,4 |
stw $16,$29,0 |
and $16,$4,0xFF |
jal rmcrs |
add $8,$0,' ' |
bltu $16,$8,dspout2 |
add $8,$0,scrptr |
ldw $9,$8,0 |
or $16,$16,0x07 << 8 |
stw $16,$9,0 |
add $9,$9,4 |
stw $9,$8,0 |
add $8,$0,scrcol |
ldw $9,$8,0 |
add $9,$9,1 |
stw $9,$8,0 |
add $10,$0,80 |
bne $9,$10,dspout1 |
jal docr |
jal dolf |
dspout1: |
jal stcrs |
ldw $16,$29,0 |
ldw $31,$29,4 |
add $29,$29,8 |
jr $31 |
|
dspout2: |
add $8,$0,0x0D |
bne $16,$8,dspout3 |
jal docr |
j dspout1 |
|
dspout3: |
add $8,$0,0x0A |
bne $16,$8,dspout4 |
jal dolf |
j dspout1 |
|
dspout4: |
add $8,$0,0x08 |
bne $16,$8,dspout5 |
jal dobs |
j dspout1 |
|
dspout5: |
j dspout1 |
|
; do carriage return |
docr: |
sub $29,$29,4 |
stw $31,$29,0 |
add $8,$0,scrcol |
stw $0,$8,0 |
jal calcp |
ldw $31,$29,0 |
add $29,$29,4 |
jr $31 |
|
; do linefeed |
dolf: |
sub $29,$29,4 |
stw $31,$29,0 |
add $8,$0,scrrow |
ldw $9,$8,0 |
add $10,$0,29 |
beq $9,$10,dolf1 |
add $9,$9,1 |
stw $9,$8,0 |
jal calcp |
j dolf2 |
dolf1: |
jal scrscr |
dolf2: |
ldw $31,$29,0 |
add $29,$29,4 |
jr $31 |
|
; do backspace |
dobs: |
sub $29,$29,4 |
stw $31,$29,0 |
add $8,$0,scrcol |
ldw $9,$8,0 |
beq $9,$0,dobs1 |
sub $9,$9,1 |
stw $9,$8,0 |
jal calcp |
dobs1: |
ldw $31,$29,0 |
add $29,$29,4 |
jr $31 |
|
; remove cursor |
rmcrs: |
add $8,$0,scrptr |
ldw $8,$8,0 |
add $9,$0,scrchr |
ldw $10,$9,0 |
stw $10,$8,0 |
jr $31 |
|
; set cursor |
stcrs: |
add $8,$0,scrptr |
ldw $8,$8,0 |
add $9,$0,scrchr |
ldw $10,$8,0 |
stw $10,$9,0 |
add $10,$0,(0x87 << 8) | '_' |
stw $10,$8,0 |
jr $31 |
|
; calculate screen pointer based on row and column |
calcp: |
add $9,$0,dspbase |
add $8,$0,scrrow |
ldw $10,$8,0 |
sll $10,$10,7+2 |
add $9,$9,$10 |
add $8,$0,scrcol |
ldw $10,$8,0 |
sll $10,$10,0+2 |
add $9,$9,$10 |
add $8,$0,scrptr |
stw $9,$8,0 |
jr $31 |
|
; clear screen |
clrscr: |
add $11,$0,(0x07 << 8) | ' ' |
add $8,$0,dspbase |
add $9,$0,30 |
clrscr1: |
add $10,$0,80 |
clrscr2: |
stw $11,$8,0 |
add $8,$8,4 |
sub $10,$10,1 |
bne $10,$0,clrscr2 |
add $8,$8,(128-80)*4 |
sub $9,$9,1 |
bne $9,$0,clrscr1 |
jr $31 |
|
; scroll screen |
scrscr: |
add $8,$0,dspbase |
add $9,$0,29 |
scrscr1: |
add $10,$0,80 |
scrscr2: |
ldw $11,$8,128*4 |
stw $11,$8,0 |
add $8,$8,4 |
sub $10,$10,1 |
bne $10,$0,scrscr2 |
add $8,$8,(128-80)*4 |
sub $9,$9,1 |
bne $9,$0,scrscr1 |
add $11,$0,(0x07 << 8) | ' ' |
add $10,$0,80 |
scrscr3: |
stw $11,$8,0 |
add $8,$8,4 |
sub $10,$10,1 |
bne $10,$0,scrscr3 |
jr $31 |
|
;*************************************************************** |
|
.bss |
.align 4 |
|
scrptr: |
.word 0 |
|
scrrow: |
.word 0 |
|
scrcol: |
.word 0 |
|
scrchr: |
.word 0 |
/common/disasm.h
0,0 → 1,13
/* |
* disasm.h -- disassembler |
*/ |
|
|
#ifndef _DISASM_H_ |
#define _DISASM_H_ |
|
|
char *disasm(Word instr, Word locus); |
|
|
#endif /* _DISASM_H_ */ |
/common/asm.h
0,0 → 1,13
/* |
* asm.h -- assembler |
*/ |
|
|
#ifndef _ASM_H_ |
#define _ASM_H_ |
|
|
char *asmInstr(char *line, Word addr, Word *instrPtr); |
|
|
#endif /* _ASM_H_ */ |
/common/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/common/getline.c
0,0 → 1,136
/* |
* getline.c -- line input |
*/ |
|
|
#include "common.h" |
#include "stdarg.h" |
#include "romlib.h" |
#include "getline.h" |
|
|
#define MAX_HISTORY 20 |
|
|
static char history[MAX_HISTORY][80]; |
static int historyIndex; /* next line to be written */ |
|
|
/* |
* Get a line from the console. |
*/ |
char *getLine(char *prompt) { |
static char line[80]; |
int index; |
int historyPointer; |
char c; |
int i; |
|
printf(prompt); |
index = 0; |
historyPointer = historyIndex; |
while (1) { |
c = getchar(); |
switch (c) { |
case '\r': |
putchar('\n'); |
line[index] = '\0'; |
return line; |
case '\b': |
case 0x7F: |
if (index == 0) { |
break; |
} |
putchar('\b'); |
putchar(' '); |
putchar('\b'); |
index--; |
break; |
case 'P' & ~0x40: |
if (historyPointer == historyIndex) { |
line[index] = '\0'; |
strcpy(history[historyIndex], line); |
} |
i = historyPointer - 1; |
if (i == -1) { |
i = MAX_HISTORY - 1; |
} |
if (i == historyIndex) { |
putchar('\a'); |
break; |
} |
if (history[i][0] == '\0') { |
putchar('\a'); |
break; |
} |
historyPointer = i; |
strcpy(line, history[historyPointer]); |
printf("\r"); |
for (i = 0; i < 79; i++) { |
printf(" "); |
} |
printf("\r"); |
printf(prompt); |
printf(line); |
index = strlen(line); |
break; |
case 'N' & ~0x40: |
if (historyPointer == historyIndex) { |
putchar('\a'); |
break; |
} |
i = historyPointer + 1; |
if (i == MAX_HISTORY) { |
i = 0; |
} |
historyPointer = i; |
strcpy(line, history[historyPointer]); |
printf("\r"); |
for (i = 0; i < 79; i++) { |
printf(" "); |
} |
printf("\r"); |
printf(prompt); |
printf(line); |
index = strlen(line); |
break; |
default: |
if (c == '\t') { |
c = ' '; |
} |
if (c < 0x20 || c > 0x7E) { |
break; |
} |
putchar(c); |
line[index++] = c; |
break; |
} |
} |
/* never reached */ |
return NULL; |
} |
|
|
/* |
* Add a line to the history. |
* Don't do this if the line is empty, or if its |
* contents exactly match the previous line. |
*/ |
void addHist(char *line) { |
int lastWritten; |
|
if (*line == '\0') { |
return; |
} |
lastWritten = historyIndex - 1; |
if (lastWritten == -1) { |
lastWritten = MAX_HISTORY - 1; |
} |
if (strcmp(history[lastWritten], line) == 0) { |
return; |
} |
strcpy(history[historyIndex], line); |
if (++historyIndex == MAX_HISTORY) { |
historyIndex = 0; |
} |
} |
/common/romlib.h
0,0 → 1,34
/* |
* romlib.h -- the ROM library |
*/ |
|
|
#ifndef _ROMLIB_H_ |
#define _ROMLIB_H_ |
|
|
void debugBreak(void); |
|
int strlen(const char *s); |
int strcmp(const char *s, const char *t); |
char *strcpy(char *s, const char *t); |
char *strcat(char *s, const char *t); |
char *strchr(const char *s, char c); |
char *strtok(char *s, const char *t); |
|
unsigned long strtoul(const char *s, char **endp, int base); |
|
void qsort(void *base, int n, int size, |
int (*cmp)(const void *, const void *)); |
|
char getchar(void); |
void putchar(char c); |
void puts(const char *s); |
|
int vprintf(const char *fmt, va_list ap); |
int printf(const char *fmt, ...); |
int vsprintf(char *s, const char *fmt, va_list ap); |
int sprintf(char *s, const char *fmt, ...); |
|
|
#endif /* _ROMLIB_H_ */ |
/common/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/common/getline.h
0,0 → 1,14
/* |
* getline.h -- line input |
*/ |
|
|
#ifndef _GETLINE_H_ |
#define _GETLINE_H_ |
|
|
char *getLine(char *prompt); |
void addHist(char *line); |
|
|
#endif /* _GETLINE_H_ */ |
/common/cpu.h
0,0 → 1,40
/* |
* cpu.h -- execute instructions |
*/ |
|
|
#ifndef _CPU_H_ |
#define _CPU_H_ |
|
|
#define PSW_V 0x08000000 /* interrupt vector bit in PSW */ |
#define PSW_UM 0x04000000 /* user mode enable bit in PSW */ |
#define PSW_PUM 0x02000000 /* previous value of PSW_UM */ |
#define PSW_OUM 0x01000000 /* old value of PSW_UM */ |
#define PSW_IE 0x00800000 /* interrupt enable bit in PSW */ |
#define PSW_PIE 0x00400000 /* previous value of PSW_IE */ |
#define PSW_OIE 0x00200000 /* old value of PSW_IE */ |
#define PSW_PRIO_MASK 0x001F0000 /* bits to encode IRQ prio in PSW */ |
|
|
Word cpuGetPC(void); |
void cpuSetPC(Word addr); |
|
Word cpuGetReg(int regnum); |
void cpuSetReg(int regnum, Word value); |
|
Word cpuGetPSW(void); |
void cpuSetPSW(Word value); |
|
Bool cpuTestBreak(void); |
Word cpuGetBreak(void); |
void cpuSetBreak(Word addr); |
void cpuResetBreak(void); |
|
char *exceptionToString(int exception); |
|
void cpuStep(void); |
void cpuRun(void); |
|
|
#endif /* _CPU_H_ */ |
/common/common.h
0,0 → 1,27
/* |
* common.h -- common definitions |
*/ |
|
|
#ifndef _COMMON_H_ |
#define _COMMON_H_ |
|
|
#define PAGE_SHIFT 12 /* log2 of page size */ |
#define PAGE_SIZE (1 << PAGE_SHIFT) /* page size in bytes */ |
#define OFFSET_MASK (PAGE_SIZE - 1) /* mask for offset in page */ |
#define PAGE_MASK (~OFFSET_MASK) /* mask for page number */ |
|
|
typedef enum { false, true } Bool; /* truth values */ |
|
|
typedef unsigned int Word; /* 32 bit quantities */ |
typedef unsigned short Half; /* 16 bit quantities */ |
typedef unsigned char Byte; /* 8 bit quantities */ |
|
|
#define NULL ((void *) 0) |
|
|
#endif /* _COMMON_H_ */ |
/kbdtbls/Makefile
0,0 → 1,18
# |
# Makefile to construct the keyboard mapping tables |
# |
|
.PHONY: all install clean |
|
all: kbdtbls.s |
|
install: kbdtbls.s |
|
kbdtbls.s: mkkbdtbls |
./mkkbdtbls >kbdtbls.s |
|
mkkbdtbls: mkkbdtbls.c |
gcc -m32 -g -Wall -o mkkbdtbls mkkbdtbls.c |
|
clean: |
rm -f *~ mkkbdtbls kbdtbls.s |
/kbdtbls/mkkbdtbls.c
0,0 → 1,171
/* |
* mkkbdtbls.c -- construct keyboard translation tables |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
|
typedef struct { |
unsigned char ascii; |
unsigned char key; |
} Entry; |
|
|
Entry tbl1[] = { |
{ 0x1B, 0x76 }, |
{ '1', 0x16 }, |
{ '2', 0x1E }, |
{ '3', 0x26 }, |
{ '4', 0x25 }, |
{ '5', 0x2E }, |
{ '6', 0x36 }, |
{ '7', 0x3D }, |
{ '8', 0x3E }, |
{ '9', 0x46 }, |
{ '0', 0x45 }, |
{ '^', 0x0E }, |
{ 0x08, 0x66 }, |
{ 0x09, 0x0D }, |
{ 'q', 0x15 }, |
{ 'w', 0x1D }, |
{ 'e', 0x24 }, |
{ 'r', 0x2D }, |
{ 't', 0x2C }, |
{ 'z', 0x35 }, |
{ 'u', 0x3C }, |
{ 'i', 0x43 }, |
{ 'o', 0x44 }, |
{ 'p', 0x4D }, |
{ '\r', 0x5A }, |
{ ' ', 0x29 }, |
{ 'a', 0x1C }, |
{ 's', 0x1B }, |
{ 'd', 0x23 }, |
{ 'f', 0x2B }, |
{ 'g', 0x34 }, |
{ 'h', 0x33 }, |
{ 'j', 0x3B }, |
{ 'k', 0x42 }, |
{ 'l', 0x4B }, |
{ 'y', 0x1A }, |
{ 'x', 0x22 }, |
{ 'c', 0x21 }, |
{ 'v', 0x2A }, |
{ 'b', 0x32 }, |
{ 'n', 0x31 }, |
{ 'm', 0x3A }, |
{ ',', 0x41 }, |
{ '.', 0x49 }, |
{ '-', 0x4A }, |
{ '+', 0x5B }, |
{ '#', 0x5D }, |
{ '<', 0x61 }, |
}; |
|
|
Entry tbl2[] = { |
{ 0x1B, 0x76 }, |
{ '!', 0x16 }, |
{ '"', 0x1E }, |
{ '3', 0x26 }, |
{ '$', 0x25 }, |
{ '%', 0x2E }, |
{ '&', 0x36 }, |
{ '/', 0x3D }, |
{ '(', 0x3E }, |
{ ')', 0x46 }, |
{ '=', 0x45 }, |
{ '^', 0x0E }, |
{ 0x08, 0x66 }, |
{ 0x09, 0x0D }, |
{ 'Q', 0x15 }, |
{ 'W', 0x1D }, |
{ 'E', 0x24 }, |
{ 'R', 0x2D }, |
{ 'T', 0x2C }, |
{ 'Z', 0x35 }, |
{ 'U', 0x3C }, |
{ 'I', 0x43 }, |
{ 'O', 0x44 }, |
{ 'P', 0x4D }, |
{ '\r', 0x5A }, |
{ ' ', 0x29 }, |
{ 'A', 0x1C }, |
{ 'S', 0x1B }, |
{ 'D', 0x23 }, |
{ 'F', 0x2B }, |
{ 'G', 0x34 }, |
{ 'H', 0x33 }, |
{ 'J', 0x3B }, |
{ 'K', 0x42 }, |
{ 'L', 0x4B }, |
{ 'Y', 0x1A }, |
{ 'X', 0x22 }, |
{ 'C', 0x21 }, |
{ 'V', 0x2A }, |
{ 'B', 0x32 }, |
{ 'N', 0x31 }, |
{ 'M', 0x3A }, |
{ ';', 0x41 }, |
{ ':', 0x49 }, |
{ '_', 0x4A }, |
{ '*', 0x5B }, |
{ '\'', 0x5D }, |
{ '>', 0x61 }, |
}; |
|
|
int main(void) { |
unsigned char codes[256]; |
int i, j; |
|
for (i = 0; i < 256; i++) { |
codes[i] = '\0'; |
} |
for (i = 0; i < sizeof(tbl1)/sizeof(tbl1[0]); i++) { |
codes[tbl1[i].key] = tbl1[i].ascii; |
} |
printf(";\n"); |
printf("; keyboard code tables\n"); |
printf(";\n"); |
printf("\n"); |
printf("\t.export\txltbl1\n"); |
printf("\t.export\txltbl2\n"); |
printf("\n"); |
printf("\t.code\n"); |
printf("\t.align\t4\n"); |
printf("\n"); |
printf("xltbl1:\n"); |
for (i = 0; i < 32; i++) { |
printf("\t.byte\t"); |
for (j = 0; j < 8; j++) { |
printf("0x%02X", codes[i * 8 + j]); |
if (j < 7) { |
printf(", "); |
} |
} |
printf("\n"); |
} |
printf("\n"); |
for (i = 0; i < 256; i++) { |
codes[i] = '\0'; |
} |
for (i = 0; i < sizeof(tbl2)/sizeof(tbl2[0]); i++) { |
codes[tbl2[i].key] = tbl2[i].ascii; |
} |
printf("xltbl2:\n"); |
for (i = 0; i < 32; i++) { |
printf("\t.byte\t"); |
for (j = 0; j < 8; j++) { |
printf("0x%02X", codes[i * 8 + j]); |
if (j < 7) { |
printf(", "); |
} |
} |
printf("\n"); |
} |
return 0; |
} |
/copy/copy.s
0,0 → 1,34
; |
; copy.s -- copy a program from ROM to RAM before executing it |
; |
|
.set dst,0xC0000000 ; destination is start of RAM |
.set len,0x0000FF00 ; number of bytes to be copied |
|
.set PSW,0 ; reg # of PSW |
|
reset: |
j start |
|
interrupt: |
j interrupt ; we better have no interrupts |
|
userMiss: |
j userMiss ; and no user TLB misses |
|
start: |
mvts $0,PSW ; disable interrupts and user mode |
add $8,$0,src |
add $9,$0,dst |
add $10,$9,len |
loop: |
ldw $11,$8,0 ; copy word |
stw $11,$9,0 |
add $8,$8,4 ; bump pointers |
add $9,$9,4 |
bltu $9,$10,loop ; more? |
add $8,$0,dst ; start execution |
jr $8 |
|
; the program to be copied follows immediately |
src: |
/copy/Makefile
0,0 → 1,21
# |
# Makefile for ROM-to-RAM copy program |
# |
|
BUILD = ../../../build |
|
.PHONY: all install clean |
|
all: copy.bin |
|
install: copy.bin |
|
copy.bin: copy.o |
$(BUILD)/bin/ld -o copy.bin -m copy.map \ |
-h -rc 0xE0000000 copy.o |
|
copy.o: copy.s |
$(BUILD)/bin/as -o copy.o copy.s |
|
clean: |
rm -f *~ copy.o copy.bin copy.map |
/Makefile
0,0 → 1,25
# |
# Makefile for building the ECO32 ROM monitor |
# |
|
BUILD = ../../build |
|
DIRS = copy kbdtbls boards |
|
.PHONY: all install clean |
|
all: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i all ; \ |
done |
|
install: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i install ; \ |
done |
|
clean: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i clean ; \ |
done |
rm -f *~ |