From c9400beacff8bd1f96eb8c42411f4cb6d4d7300a Mon Sep 17 00:00:00 2001 From: Roberto Hexsel <roberto@inf.ufpr.br> Date: Tue, 28 Mar 2017 20:28:24 -0300 Subject: [PATCH] added program that turns the board into a clock --- cMIPS/bin/assemble.sh | 10 +- cMIPS/bin/compile.sh | 26 +- cMIPS/include/cMIPS.h | 27 +- cMIPS/include/cMIPSio.c | 27 ++ cMIPS/include/syn_handlers.s | 617 +++++++++++++++++++++++++++++++++++ cMIPS/include/syn_start.s | 86 ++++- cMIPS/tests/mac_chrono.c | 155 +++++++++ cMIPS/v_irx.sav | 21 +- cMIPS/v_rx.sav | 57 ++-- cMIPS/v_tx.sav | 41 +-- cMIPS/vhdl/core.vhd | 14 +- 11 files changed, 980 insertions(+), 101 deletions(-) create mode 100644 cMIPS/include/syn_handlers.s create mode 100644 cMIPS/tests/mac_chrono.c diff --git a/cMIPS/bin/assemble.sh b/cMIPS/bin/assemble.sh index 5fa45a8..39b832b 100755 --- a/cMIPS/bin/assemble.sh +++ b/cMIPS/bin/assemble.sh @@ -86,7 +86,7 @@ while true ; do ;; -n) names=true ;; - -mif|-m) miffile=true + -mif | -m | -syn ) miffile=true ;; -x) set -x ;; @@ -103,6 +103,14 @@ if [ -z $inp ] ; then usage ; exit 1 ; fi pkg_vhd="${srcVHDL}"/packageMemory.vhd +if [ $miffile = true ]; then + S="-D FOR_SYNTHESIS" ; + touch $pkg_vhd -r ${srcVHDL}/packageMemory_fpga.vhd +else + S="-U FOR_SYNTHESIS" ; + touch $pkg_vhd -r ${srcVHDL}/packageMemory_simu.vhd +fi + if [ $pkg_vhd -nt $c_ld -o $pkg_vhd -nt $c_s ] ; then "${bin}"/edMemory.sh -v || errorED || exit 1 fi diff --git a/cMIPS/bin/compile.sh b/cMIPS/bin/compile.sh index 0828bff..0bc781e 100755 --- a/cMIPS/bin/compile.sh +++ b/cMIPS/bin/compile.sh @@ -84,9 +84,8 @@ while true ; do ;; -n) names=false ;; - -mif) miffile=true - ;; - -syn) synth=true + -mif | -syn ) synth=true + miffile=true ;; -x) set -x ;; @@ -111,10 +110,22 @@ c_h="${include}"/cMIPS.h c_s="${include}"/cMIPS.s c_io="${include}"/cMIPSio # c_start="${include}"/start ## see below for synthesis version -c_hndlrs="${include}"/handlers +# c_hndlrs="${include}"/handlers ## see below for synthesis version pkg_vhd="${srcVHDL}"/packageMemory.vhd +if [ $synth = true ]; then + S="-D FOR_SYNTHESIS" ; + c_start="${include}"/syn_start + c_hndlrs="${include}"/syn_handlers + touch $pkg_vhd -r ${srcVHDL}/packageMemory_fpga.vhd +else + S="-U FOR_SYNTHESIS" ; + c_start="${include}"/start + c_hndlrs="${include}"/handlers + touch $pkg_vhd -r ${srcVHDL}/packageMemory_simu.vhd +fi + if [ $pkg_vhd -nt $c_h -o\ $pkg_vhd -nt $c_ld -o\ $pkg_vhd -nt $c_s ] ; then @@ -130,13 +141,6 @@ dat=data.bin if [ $verbose = true ]; then memory_map="-Map ${inp}.map" ; fi -if [ $synth = true ]; then - S="-D FOR_SYNTHESIS" ; - c_start="${include}"/syn_start -else - S="-U FOR_SYNTHESIS" ; - c_start="${include}"/start -fi (mips-gcc -O${level} $warn -DcMIPS -mno-gpopt -I"${include}" \ -S ${src} $S -o ${asm} || exit 1) && \ diff --git a/cMIPS/include/cMIPS.h b/cMIPS/include/cMIPS.h index 5e8b52a..2acad22 100644 --- a/cMIPS/include/cMIPS.h +++ b/cMIPS/include/cMIPS.h @@ -25,6 +25,14 @@ extern void exit(int); + +extern void cmips_delay(int); +extern void delay_us(int); +extern void delay_ms(int); + +extern void enableInterr(void); +extern void disableInterr(void); + extern void print(int); extern void to_stdout(char c); extern int from_stdin(void); @@ -33,27 +41,22 @@ extern void writeInt(int); extern void writeClose(void); extern int readInt(int*); extern void dumpRAM(void); +extern int print_sp(void); -extern void cmips_delay(int); -extern void delay_us(int); -extern void delay_ms(int); +extern char *memcpy(char*, const char*, int); +extern char *memset(char*, const int, int); // external counter (peripheral) extern void startCounter(int, int); extern void stopCounter(void); extern int readCounter(void); -extern void enableInterr(void); -extern void disableInterr(void); - // internal counter, CP0 register COUNT extern int startCount(void); extern int stopCount(void); extern int readCount(void); -extern char *memcpy(char*, const char*, int); -extern char *memset(char*, const int, int); - +// LCD display (Macnica board) extern void LCDinit(void); extern int LCDprobe(void); extern int LCDset(int); @@ -63,13 +66,15 @@ extern void LCDtopLine(void); extern void LCDbotLine(void); extern void LCDgotoxy(int, int); extern void LCDputc(char); +extern void LCDprint(unsigned int); -extern void DSP7SEGput(int MSD, int MSdot, int lsd, int lsdot); +// 7-segment display and keyboard (Macnica board) +extern void DSP7SEGput(int, int, int, int); extern int KBDget(void); extern int SWget(void); -// struct to access the system statistics "peripheral" +// struct to access the cache system statistics "peripheral" typedef struct sStats { int dc_ref; // data cache references int dc_rd_hit; // data cache read-hits diff --git a/cMIPS/include/cMIPSio.c b/cMIPS/include/cMIPSio.c index 6cb11fa..5e04c49 100644 --- a/cMIPS/include/cMIPSio.c +++ b/cMIPS/include/cMIPSio.c @@ -350,6 +350,33 @@ void LCDputc(char c) { } } +#define conv(c) ((c<10)?((c)+0x30):((c)+('a'-10))) + +// write an integer to the display +void LCDprint(unsigned int n) { + int k; + + k = (n >>28); + LCDput( conv(k) ); + k = (n<< 4)>>28; + LCDput( conv(k) ); + + k = (n<< 8)>>28; + LCDput( conv(k) ); + k = (n<<12)>>28; + LCDput( conv(k) ); + + k = (n<<16)>>28; + LCDput( conv(k) ); + k = (n<<20)>>28; + LCDput( conv(k) ); + + k = (n<<24)>>28; + LCDput( conv(k) ); + k = (n<<28)>>28; + LCDput( conv(k) ); +} + //----------------------------------------------------------------------- diff --git a/cMIPS/include/syn_handlers.s b/cMIPS/include/syn_handlers.s new file mode 100644 index 0000000..6f02f37 --- /dev/null +++ b/cMIPS/include/syn_handlers.s @@ -0,0 +1,617 @@ + # interrupt handlers + .include "cMIPS.s" + .text + .set noreorder # do not reorder instructions + .set noat # do not use register $1 as $at + .align 2 + + .set M_StatusIEn,0x0000e011 # STATUS.intEn=1, user mode, EXL=0 + + #================================================================ + # interrupt handler for external counter attached to IP5=HW3 + # for extCounter address see vhdl/packageMemory.vhd + # + # counter set to interrupt 4 times per second (12,500,000*20ns) + # + .bss + .align 2 + .global _counter_val # accumulate number of interrupts +_counter_val: .space 4 +_counter_saves: .space 8*4 # area to save up to 8 registers + # _counter_saves[0]=$a0, [1]=$a1, [2]=$a2, [3]=$a3, ... + + .set HW_counter_value,(0xc0000000 | 0x00bebc20) # 12,500,000 + + .text + .set noreorder + .global extCounter + .ent extCounter + +extCounter: + lui $k0, %hi(HW_counter_addr) + ori $k0, $k0, %lo(HW_counter_addr) + sw $zero, 0($k0) # Reset counter, remove interrupt request + + #---------------------------------- + # if you change this handler, then save additional registers + # lui $k1, %hi(_counter_saves) + # ori $k1, $k1, %lo(_counter_saves) + # sw $a0, 0*4($k1) + # sw $a1, 1*4($k1) + #---------------------------------- + + lui $k1, %hi(HW_counter_value) + ori $k1, $k1, %lo(HW_counter_value) + sw $k1, 0($k0) # Reload counter so it starts again + + lui $k0, %hi(_counter_val) # Increment interrupt event counter + ori $k0, $k0, %lo(_counter_val) + lw $k1,0($k0) + nop + addiu $k1,$k1,1 + sw $k1,0($k0) + + #---------------------------------- + # if you changed this handler, then restore those same registers + # lui $k1, %hi(_counter_saves) + # ori $k1, $k1, %lo(_counter_saves) + # lw $a0, 0*4($k1) + # lw $a1, 1*4($k1) + #---------------------------------- + + mfc0 $k0, c0_status # Read STATUS register + ori $k0, $k0, M_StatusIEn # but do not modify its contents + mtc0 $k0, c0_status # except for re-enabling interrupts + ehb + eret # Return from interrupt + .end extCounter + #---------------------------------------------------------------- + + + #================================================================ + # interrupt handler for UART attached to IP6=HW4 + # for UART's address see vhdl/packageMemory.vhd + # + .global Ud, _uart_buff + .bss + .align 2 +Ud: +rx_hd: .space 4 +rx_tl: .space 4 +rx_q: .space 16 # reception queue and pointers +tx_hd: .space 4 +tx_tl: .space 4 +tx_q: .space 16 # transmission queue and pointers +nrx: .space 4 # characters in RX_queue +ntx: .space 4 # spaces left in TX_queue + +_uart_buff: .space 16*4 # up to 16 registers to be saved here + + .set UART_rx_irq,0x08 + .set UART_tx_irq,0x10 + + .text + .set noreorder + .global UARTinterr + .ent UARTinterr + + # _uart_buff[0]=UARTstatus, [1]=UARTcontrol, [2]=data_inp, [3]=new, + # [4]=$ra, [5]=$a0, [6]=$a1, [7]=$a2, [8]=$a3 + +UARTinterr: + lui $k0, %hi(_uart_buff) # get buffer's address + ori $k0, $k0, %lo(_uart_buff) + + sw $a0, 5*4($k0) # save registers $a0,$a1, others? + sw $a1, 6*4($k0) + + lui $a0, %hi(HW_uart_addr)# get device's address + ori $a0, $a0, %lo(HW_uart_addr) + + lw $k1, 0($a0) # Read status, remove interrupt request + nop + sw $k1, 0*4($k0) # and save UART status to memory + + #---------------------------------- + # while you are developing the complete handler, + # uncomment the line below and comment out lines up to UARTret + # .include "../tests/handlerUART.s" + #---------------------------------- + + andi $a1, $k1, UART_rx_irq # Is this reception? + beq $a1, $zero, UARTret # no, ignore it and return + nop + + # handle reception + lw $a1, 4($a0) # Read data from device + nop # and store it to UART's buffer + sw $a1, 2*4($k0) # and return from interrupt + addiu $a1, $zero, 1 + sw $a1, 3*4($k0) # Signal new arrival + +UARTret: + lw $a1, 6*4($k0) # restore registers $a0,$a1, others? + lw $a0, 5*4($k0) + + mfc0 $k0, c0_status # Read STATUS register + ori $k0, $k0, M_StatusIEn # but do not modify its contents + mtc0 $k0, c0_status # except for re-enabling interrupts + eret # Return from interrupt + .end UARTinterr + #---------------------------------------------------------------- + + + #================================================================ + # handler for COUNT-COMPARE registers -- IP7=HW5 + .text + .set noreorder + .equ num_cycles, 64 + .global countCompare + .ent countCompare +countCompare: + mfc0 $k1,c0_count # read COUNT + addiu $k1,$k1,num_cycles # set next interrupt in so many ticks + mtc0 $k1,c0_compare # write to COMPARE to clear IRQ + + mfc0 $k0, c0_status # Read STATUS register + ori $k0, $k0, M_StatusIEn # but do not modify its contents + mtc0 $k0, c0_status # except for re-enabling interrupts + eret # Return from interrupt + .end countCompare + #---------------------------------------------------------------- + + + #================================================================ + # startCount enables the COUNT register, returns new CAUSE + # CAUSE.dc <= 0 to enable counting + #---------------------------------------------------------------- + .text + .set noreorder + .global startCount + .ent startCount +startCount: + mfc0 $v0, c0_cause + lui $v1, 0xf7ff + ori $v1, $v1, 0xffff + and $v0, $v0, $v1 + jr $ra + mtc0 $v0, c0_cause + .end startCount + #---------------------------------------------------------------- + + + #================================================================ + # stopCount disables the COUNT register, returns new CAUSE + # CAUSE.dc <= 1 to disable counting + #---------------------------------------------------------------- + .text + .set noreorder + .global stopCount + .ent stopCount +stopCount: + mfc0 $v0, c0_cause + lui $v1, 0x0800 + or $v0, $v0, $v1 + jr $ra + mtc0 $v0, c0_cause + .end stopCount + #---------------------------------------------------------------- + + + #================================================================ + # readCount returns the value of the COUNT register + #---------------------------------------------------------------- + .text + .set noreorder + .global readCount + .ent readCount +readCount: + mfc0 $v0, c0_count + jr $ra + nop + .end readCount + #---------------------------------------------------------------- + + + #================================================================ + # functions to enable and disable interrupts, both return STATUS + .text + .set noreorder + .global enableInterr,disableInterr + .ent enableInterr +enableInterr: + mfc0 $v0, c0_status # Read STATUS register + ori $v0, $v0, 1 # and enable interrupts + mtc0 $v0, c0_status + nop + jr $ra # return updated STATUS + nop + .end enableInterr + + .ent disableInterr +disableInterr: + mfc0 $v0, c0_status # Read STATUS register + addiu $v1, $zero, -2 # and disable interrupts + and $v0, $v0, $v1 # -2 = 0xffff.fffe + mtc0 $v0, c0_status + nop + jr $ra # return updated STATUS + nop + .end disableInterr + #---------------------------------------------------------------- + + + #================================================================ + ## TLB handlers + ## page table entry is { EntryLo0, int0, EntryLo1, int1 } + ## int{0,1} is + ## { fill_31..6, Modified_5, Used_4, Writable_3, eXecutable_2, + ## Status_10 }, + ## Status: 00=unmapped, 01=mapped, 10=secondary_storage, 11=panic + #================================================================ + + + #================================================================ + # handle TLB Modified exception -- store to page with bit dirty=0 + # + # (a) fix TLB entry, by setting dirty=1 ; + # (b) check permissions in PT entry and (maybe) kill the process + # OR mark PT entry as Used and Modified, then + # update TLB entry. + # + .global _excp_saves + .global _excp_0180ret + .global handle_Mod + .set noreorder + + .ent handle_Mod +handle_Mod: # EntryHi points to offending TLB entry + tlbp # what is the offender's index? + lui $k1, %hi(_excp_saves) + ori $k1, $k1, %lo(_excp_saves) + sw $a0, 9*4($k1) # save registers + sw $a1, 10*4($k1) + sw $a2, 11*4($k1) + + mfc0 $a0, c0_badvaddr + andi $a0, $a0, 0x1000 # check if even or odd page + beq $a0, $zero, M_even + mfc0 $a0, c0_context + +M_odd: addi $a2, $a0, 12 # address for odd entry + mfc0 $k0, c0_entrylo1 + ori $k0, $k0, 0x0004 # mark TLB entry as dirty/writable + j M_test + mtc0 $k0, c0_entrylo1 + +M_even: addi $a2, $a0, 4 # address for even entry + mfc0 $k0, c0_entrylo0 + ori $k0, $k0, 0x0004 # mark TLB entry as dirty/writable + mtc0 $k0, c0_entrylo0 + +M_test: lw $a1, 0($a2) # read PT[badVAddr] + mfc0 $k0, c0_badvaddr # get faulting address + andi $a0, $a1, 0x0001 # check if page is mapped + beq $a0, $zero, M_seg_fault # no, abort simulation + nop + + andi $a0, $a1, 0x0008 # check if page is writable + beq $a0, $zero, M_prot_viol # no, abort simulation + nop + + andi $a0, $a1, 0x0002 # check if page is in secondary memory + bne $a0, $zero, M_sec_mem # yes, abort simulation + nop + + mfc0 $a0, c0_epc # check if fault is on an instruction + beq $a0, $k0, M_prot_viol # k0 is badVAddr, if so, abort + nop + + ori $a1, $a1, 0x0030 # mark PT entry as modified, used + sw $a1, 0($a2) + + tlbwi # write entry with dirty bit=1 back to TLB + + lw $a0, 9*4($k1) # restore saved registers and return + lw $a1, 10*4($k1) + j _excp_0180ret + lw $a2, 11*4($k1) + +M_seg_fault: # print message and abort simulation + la $k1, x_IO_BASE_ADDR + sw $k0, 0($k1) + jal cmips_kmsg + la $k1, 3 # segmentation fault + nop + nop + nop + wait 0x41 + +M_prot_viol: # print message and abort simulation + la $k1, x_IO_BASE_ADDR + sw $k0, 0($k1) + jal cmips_kmsg + la $k1, 2 # protection violation + nop + nop + nop + wait 0x42 + +M_sec_mem: # print message and abort simulation + la $k1, x_IO_BASE_ADDR + sw $k0, 0($k1) + jal cmips_kmsg + la $k1, 4 # secondary memory + nop + nop + nop + wait 0x43 + + .end handle_Mod + #---------------------------------------------------------------- + + + #================================================================ + # handle TLB Load exception: double-fault caused by a TLB miss + # to the Page Table -- mapping pointing to PT is not on TLB + # + # (a) fix the fault by (re)loading the mapping into TLB[4]; + # (b) check permissions in PT entry and (maybe) kill the process. + # + .global handle_TLBL + .global _PT + .set MIDDLE_RAM, (x_DATA_BASE_ADDR + (x_DATA_MEM_SZ/2)) + + .ent handle_TLBL +handle_TLBL: # EntryHi points to offending TLB entry + tlbp # probe it to find the offender's index + lui $k1, %hi(_excp_saves) + ori $k1, $k1, %lo(_excp_saves) + sw $a0, 9*4($k1) + sw $a1, 10*4($k1) + sw $a2, 11*4($k1) + + mfc0 $a0, c0_badvaddr + la $a1, (_PT + (x_INST_BASE_ADDR >>13)*16) + + slt $a2, $a0, $a1 # a2 <- (badVAddr <= PageTable) + bne $a2, $zero, L_chks # fault is not to PageTable + nop + + # this is same code as in start.s + # get physical page number for two pages at the bottom of PageTable + la $a0, ( MIDDLE_RAM >>13 )<<13 + mtc0 $a0, c0_entryhi # tag for bottom double-page + + la $a0, ( (MIDDLE_RAM + 0*4096) >>12 )<<6 + ori $a1, $a0, 0b00000000000000000000000000000111 # ccc=0, d,v,g1 + mtc0 $a1, c0_entrylo0 # bottom page (even) + + la $a0, ( (MIDDLE_RAM + 1*4096) >>12 )<<6 + ori $a1, $a0, 0b00000000000000000000000000000111 # ccc=0, d,v,g1 + mtc0 $a1, c0_entrylo1 # bottom page + 1 (odd) + + # and write it to TLB[4] + li $k0, 4 + mtc0 $k0, c0_index + tlbwi + j L_ret # all work done, return + nop + +L_chks: andi $a0, $a0, 0x1000 # check if even or odd page + beq $a0, $zero, L_even + mfc0 $a0, c0_context + +L_odd: j L_test + addi $a2, $a0, 12 # address for odd intLo1 entry + +L_even: addi $a2, $a0, 4 # address for even intLo0 entry + +L_test: lw $a1, 0($a2) # get intLo{0,1} + mfc0 $k0, c0_badvaddr # get faulting address for printing + andi $a0, $a1, 0x0001 # check if page is mapped + beq $a0, $zero, M_seg_fault # no, abort simulation + nop + + andi $a0, $a1, 0x0002 # check if page is in secondary memory + bne $a0, $zero, M_sec_mem # yes, abort simulation + nop + + ori $a1, $a1, 0x0010 # mark PT entry as used + sw $a1, 0($a2) + + # if this were handler_TLBS, now is the time to also mark the + # PT entry as Modified + +L_ret: lw $a0, 9*4($k1) # nothing else to do, return + lw $a1, 10*4($k1) + j _excp_0180ret + lw $a2, 11*4($k1) + + .end handle_TLBL + #---------------------------------------------------------------- + + + #================================================================ + # purge an entry from the TLB + # int TLB_purge(void *V_addr) + # returns 0 if V_addr purged, 1 if V_addr not in TLB (probe failure) + # + .text + .set noreorder + .ent TLB_purge +TLB_purge: + srl $a0, $a0, 13 # clear out in-page address bits + sll $a0, $a0, 13 # + mtc0 $a0, c0_entryhi + nop + tlbp # probe the TLB + nop + mfc0 $a0, c0_index # check for hit + srl $a0, $a0, 31 # keeo only MSbit + bne $a0, $zero, pu_miss # address not in TLB + move $v0, $a0 # V_addr not in TLB + + tlbr # read the entry + li $a0, -8192 # -8192 = 0xffff.e000 + mtc0 $a0, c0_entryhi # and write an un-mapped address to tag + + addi $v0, $zero, -3 # -3 = 0xffff.fffd to clear valid bit + mfc0 $a0, c0_entrylo0 # invalidate the mappings + and $a0, $v0, $a0 + mtc0 $a0, c0_entrylo0 + + mfc0 $a0, c0_entrylo1 + and $a0, $v0, $a0 + mtc0 $a0, c0_entrylo1 + move $v0, $zero # V_addr was purged from TLB + + tlbwi # write invalid mappings to TLB + ehb + +pu_miss: jr $ra + nop + .end TLB_purge + ##--------------------------------------------------------------- + + + + #================================================================ + # delays processing by approx 4*$a0 processor cycles + .text + .set noreorder + .global cmips_delay, delay_cycle, delay_us, delay_ms + .ent cmips_delay +delay_cycle: +cmips_delay: + addiu $a0, $a0, -1 + nop + bne $a0, $zero, cmips_delay + nop + jr $ra + nop + .end cmips_delay + #---------------------------------------------------------------- + + #================================================================ + # delays processing by $a0 times 1 microsecond + # loop takes 4 cycles = 80ns @ 50MHz + # 1.000ns / 80 = 12.5 + # multiply by 2 (sll), add 1, multiply by 12, divide by 2 (sra) + .text + .set noreorder + .ent delay_us +delay_us: + sll $a0, $a0, 1 + addiu $a0, $a0, 1 + li $v0, 12 + mult $v0, $a0 + nop + mflo $a0 + sra $a0, $a0, 1 +_d_us: addiu $a0, $a0, -1 + nop + bne $a0, $zero, _d_us + nop + jr $ra + nop + .end delay_us + #---------------------------------------------------------------- + + #================================================================ + # delays processing by $a0 times 1 msecond + # loop takes 4 cycles = 80ns @ 50MHz + # 1.000.000ns / 80 = 12500 + .text + .set noreorder + .ent delay_ms +delay_ms: + li $v0, 12500 + mult $v0, $a0 + nop + mflo $a0 +_d_ms: addiu $a0, $a0, -1 + nop + bne $a0, $zero, _d_ms + nop + jr $ra + nop + .end delay_ms + #---------------------------------------------------------------- + + + #================================================================ + # print a message from within "the kernel" + # void cmips_kmsg( $k1 ) + # this function preserves registers other than k0,k1 + # + .bss + .align 2 +_kmsg_saves: .space 4*4 # area to save 4 registers + # _kmsg_saves[0]=$a0, [1]=$a1, [2]=$a2, [3]=$a3 + + .text + .align 2 + .set noreorder + .set noat + .equ stdout,(x_IO_BASE_ADDR + 1*x_IO_ADDR_RANGE); + + .global cmips_kmsg + .ent cmips_kmsg +cmips_kmsg: + lui $k0, %hi(_kmsg_saves) + ori $k0, $k0, %lo(_kmsg_saves) + sw $a0, 0*4($k0) + sw $a1, 1*4($k0) + sw $a2, 2*4($k0) + + lui $a1, %hi(_kmsg_list) + ori $a1, $a1, %lo(_kmsg_list) + + sll $k1, $k1, 2 # adjust index onto table + addu $a1, $a1, $k1 + lw $a1, 0($a1) # de-reference pointer + + lui $a2, %hi(stdout) + ori $a2, $a2, %lo(stdout) + +k_for: lbu $a0, 0($a1) + addiu $a1, $a1, 1 + bne $a0, $zero, k_for + sb $a0, 0($a2) # send it to simulator's stdout + + lw $a0, 0*4($k0) + lw $a1, 1*4($k0) + jr $ra + lw $a2, 2*4($k0) + + .end cmips_kmsg + + .equ kmsg_interr,0 + .equ kmsg_excep,1 + + .section .rodata + .align 2 +_kmsg_interr: .asciiz "\n\t00 - interrupt\n\n" +_kmsg_excep: .asciiz "\n\t01 - exception\n\n" +_kmsg_prot_viol: .asciiz "\n\t02 - protection violation\n\n" +_kmsg_seg_fault: .asciiz "\n\t03 - segmentation fault\n\n" +_kmsg_sec_mem: .asciiz "\n\t04 - in secondary memory\n\n" + + .global _kmsg_list + .section .rodata + .align 2 +_kmsg_list: + .word _kmsg_interr,_kmsg_excep, _kmsg_prot_viol, _kmsg_seg_fault + .word _kmsg_sec_mem + + ## + ## need this so the allocation of the PageTable does not break B^( + ## + .section .data + .align 2 +_end_of_data: + .word 0 + + #---------------------------------------------------------------- + diff --git a/cMIPS/include/syn_start.s b/cMIPS/include/syn_start.s index 40ce6a7..bb87e88 100644 --- a/cMIPS/include/syn_start.s +++ b/cMIPS/include/syn_start.s @@ -67,7 +67,6 @@ _start: nop # set STATUS, cop0, hw interrupt IRQ7,IRQ6,IRQ5 enabled, user mode li $k0, 0x1000e011 mtc0 $k0, cop0_STATUS - j main nop @@ -77,7 +76,7 @@ _start: nop ## exit: _exit: la $k0, HW_dsp7seg_addr # 7 segment display - li $k1, 0x0311 # display .1.1 + li $k1, 0x0300 # display .0.0 sw $k1, 0($k0) # write to 7 segment display hexit: j hexit # wait forever @@ -85,6 +84,15 @@ hexit: j hexit # wait forever .end _start + ## + ## read contants of the stack-pointer (for debugging) + ## + .global print_sp + .ent print_sp +print_sp: + jr $ra + move $v0, $sp + .end print_sp ## ##================================================================ @@ -139,7 +147,8 @@ h0100: j h0100 # wait forever .org x_EXCEPTION_0180,0 _excp_0180: la $k0, HW_dsp7seg_addr # 7 segment display - li $k1, 0x0377 # display .7.7 + mfc0 $k1, c0_cause + andi $k1, $k1, 0x07f # display .7.7 sw $k1, 0($k0) # write to 7 segment display h0180: j h0180 # wait forever nop @@ -157,17 +166,76 @@ heret: j heret # wait forever nop + ## ##=============================================================== ## interrupt handlers at exception vector 0200 ## - .org x_EXCEPTION_0200,0 + # declare all handlers here, these must be in file syn_handlers.s + .extern countCompare # IRQ7 = hwIRQ5, Cop0 counter + .extern UARTinterr # IRQ6 - hwIRQ4, see vhdl/tb_cMIPS.vhd + .extern extCounter # IRQ5 - hwIRQ3, see vhdl/tb_cMIPS.vhd + + .set M_CauseIM,0x0000e000 # keep bits 15..8 -> IM = IP + .set M_StatusIEn,0xe011 # user mode, enable all interrupts, EXL=0 + + .set noreorder + + .org x_EXCEPTION_0200,0 # exception vector_200, interrupt handlers + .ent _excp_0200 _excp_0200: - la $k0, HW_dsp7seg_addr # 7 segment display - li $k1, 0x0366 # display .6.6 - sw $k1, 0($k0) # write to 7 segment display -h0200: j h0200 # wait forever - nop + mfc0 $k0, c0_cause + andi $k0, $k0, M_CauseIM # Keep only IP bits from Cause + mfc0 $k1, c0_status + and $k0, $k0, $k1 # and mask with IM bits + + srl $k0, $k0, 10 # keep only 3 MS bits of IP (irq7..5) + lui $k1, %hi(handlers_tbl) # plus displacement in j-table of 8 bytes + ori $k1, $k1, %lo(handlers_tbl) + add $k1, $k1, $k0 + nop + jr $k1 + nop + + + ## the code for each handler must repeat the exception return + ## sequence shown below in excp_0200ret. +handlers_tbl: + j dismiss # no request: 000 + nop + + j extCounter # lowest priority, IRQ5: 001 + nop + + j UARTinterr # mid priority, IRQ6: 01x + nop + j UARTinterr + nop + + j countCompare # highest priority, IRQ7: 1xx + nop + j countCompare + nop + j countCompare + nop + j countCompare + nop + + +dismiss: # No pending request, must have been noise + # do nothing and return + +_excp_0200ret: + mfc0 $k0, c0_status # Read STATUS register + ori $k0, $k0, M_StatusIEn # and re-enable interrupts + mtc0 $k0, c0_status # else keep as it was on int entry + eret # Return from interrupt + nop + + .end _excp_0200 + #----------------------------------------------------------------- + + ## diff --git a/cMIPS/tests/mac_chrono.c b/cMIPS/tests/mac_chrono.c new file mode 100644 index 0000000..d9605c3 --- /dev/null +++ b/cMIPS/tests/mac_chrono.c @@ -0,0 +1,155 @@ +// +// chronometer on the LCD display +// +// external counter interrupts 4 times per second +// displays shows a tumbling star plus counter that increments every second +// + +#include "cMIPS.h" + +extern int _counter_val; + +int conv1(int); + +#define FALSE (0==1) +#define TRUE !FALSE + +#define QUARTER 12500000 + +int main(void) { + int i, j, k; + volatile int old_val; + int sec, min, hour; + + LCDinit(); + + LCDtopLine(); + +#if 1 + LCDput(' '); + LCDput('H'); + LCDput('e'); + LCDput('l'); + LCDput('l'); + LCDput('o'); + LCDput(' '); + LCDput('w'); + LCDput('o'); + LCDput('r'); + LCDput('l'); + LCDput('d'); + LCDput('!'); +#else + LCDprint( print_sp() ); +#endif + + LCDbotLine(); + + _counter_val = 0; // variable to accumulate number of interrupts + + old_val = _counter_val; + + enableInterr(); + startCounter(QUARTER,TRUE); // counter will interrupt after N cycles + + sec = min = hour = 0; + + i = 0; + + while (TRUE) { + + while (old_val == _counter_val) {// wait for interrupt + delay_us(i); + } + + old_val = _counter_val; + + switch(i) { + case 0: + j = 0x09; break; + case 1: + j = 0x0b; break; + case 2: + j = 0x0c; break; + default: + j = 0xa; i = -1; sec += 1 ; break; + }; + i += 1; + + LCDgotoxy(1, 2); + LCDput(j); + + if (sec == 60) { + min += 1; + sec = 0; + } + + if (min == 60) { + hour += 1; + min = 0; + } + + LCDgotoxy(4, 2); + +#define conv(a) ((a<10)?((a)+0x30):((a)+('a'-10))) + + k = (hour>>4) & 0x0f; + LCDput( conv(k) ); + k = hour & 0x0f; + LCDput( conv(k) ); + + LCDput(':'); + + k = (min>>4) & 0x0f; + LCDput( conv(k) ); + k = min & 0x0f; + LCDput( conv(k) ); + + LCDput(':'); + + k = (sec>>4) & 0x0f; + LCDput( conv(k) ); + k = sec & 0x0f; + LCDput( conv(k) ); + + } + + return 0; + +} + + + +int conv1(int c) { + int i; + + switch(c) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + i = c + 0x30; ; break; + case 10: + i = 'a'; break; + case 11: + i = 'b'; break; + case 12: + i = 'c'; break; + case 13: + i = 'd'; break; + case 14: + i = 'e'; break; + case 15: + i = 'f'; break; + default: + i = '*'; + } + + return(i); +} diff --git a/cMIPS/v_irx.sav b/cMIPS/v_irx.sav index 66c2a0e..a2b570a 100644 --- a/cMIPS/v_irx.sav +++ b/cMIPS/v_irx.sav @@ -1,20 +1,20 @@ [*] [*] GTKWave Analyzer v3.3.37 (w)1999-2012 BSI -[*] Sun May 17 23:47:43 2015 +[*] Tue Mar 28 23:27:02 2017 [*] [dumpfile] "/home/roberto/cMIPS/v_cMIPS.vcd" -[dumpfile_mtime] "Sun May 17 23:34:01 2015" -[dumpfile_size] 24210019 +[dumpfile_mtime] "Tue Mar 28 23:24:11 2017" +[dumpfile_size] 24414101 [savefile] "/home/roberto/cMIPS/v_irx.sav" -[timestart] 6435000000 -[size] 1200 908 -[pos] 676 118 -*-29.000000 7800000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[timestart] 14501000000 +[size] 1200 905 +[pos] 676 70 +*-30.000000 7800000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] u_simple_uart. [sst_width] 210 [signals_width] 221 [sst_expanded] 1 -[sst_vpaned_height] 266 +[sst_vpaned_height] 269 @28 clk @22 @@ -23,8 +23,6 @@ u_core.pc[31:0] - decode, reg fetch @22 u_core.rf_instruction[31:0] -u_core.regs_a[31:0] -u_core.regs_b[31:0] @200 - exec @24 @@ -72,7 +70,7 @@ u_simple_uart.u_uart.s_ctrl u_simple_uart.u_uart.ctrl[7:0] @28 u_simple_uart.u_uart.s_rx -@22 +@821 u_simple_uart.u_uart.rxreg[7:0] @28 u_simple_uart.irq @@ -93,5 +91,6 @@ u_simple_uart.u_uart.rxdat u_uart_remota.tx_dbg_st[31:0] @28 u_uart_remota.outdat +u_uart_remota.tx_clk [pattern_trace] 1 [pattern_trace] 0 diff --git a/cMIPS/v_rx.sav b/cMIPS/v_rx.sav index 2b871ff..225ae46 100644 --- a/cMIPS/v_rx.sav +++ b/cMIPS/v_rx.sav @@ -1,22 +1,22 @@ [*] [*] GTKWave Analyzer v3.3.37 (w)1999-2012 BSI -[*] Fri Apr 8 16:29:19 2016 +[*] Tue Mar 28 23:23:27 2017 [*] [dumpfile] "/home/roberto/cMIPS/v_cMIPS.vcd" -[dumpfile_mtime] "Fri Apr 8 13:54:30 2016" -[dumpfile_size] 11860622 +[dumpfile_mtime] "Tue Mar 28 23:18:27 2017" +[dumpfile_size] 12342617 [savefile] "/home/roberto/cMIPS/v_rx.sav" -[timestart] 1652600000 -[size] 1133 1018 -[pos] -1 -1 -*-26.000000 1820000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[timestart] 0 +[size] 1133 881 +[pos] 40 -1 +*-31.000000 2283000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] u_core. [treeopen] u_core.u_alu. [treeopen] u_simple_uart. [sst_width] 210 [signals_width] 218 [sst_expanded] 1 -[sst_vpaned_height] 304 +[sst_vpaned_height] 255 @28 clk @22 @@ -49,6 +49,14 @@ u_core.mm_wrmem u_core.data_inp[31:0] u_core.data_out[31:0] @200 +- write-back +@28 +u_core.wb_muxc[2:0] +u_core.wb_wreg +@22 +u_core.wb_a_c[4:0] +u_core.wb_c[31:0] +@200 - UART @28 u_simple_uart.u_uart.rts @@ -64,42 +72,21 @@ u_simple_uart.u_uart.ctrl[7:0] @24 u_simple_uart.u_uart.rxcpu_dbg_st[31:0] u_simple_uart.u_uart.rx_dbg_st[31:0] -@29 +@28 u_simple_uart.u_uart.s_rx @22 u_simple_uart.u_uart.rxreg[7:0] @28 -u_simple_uart.u_uart.interr_rx_full -@200 -- transmission circuit -@24 -u_simple_uart.u_uart.txcpu_dbg_st[31:0] -u_simple_uart.u_uart.tx_dbg_st[31:0] -@22 -u_simple_uart.u_uart.txreg[7:0] -@28 -u_simple_uart.u_uart.txclk -u_simple_uart.u_uart.txdat -u_simple_uart.u_uart.interr_tx_empty +u_simple_uart.u_uart.sta_recv_sto[9:0] +u_simple_uart.u_uart.rxdat +@29 +u_simple_uart.u_uart.rxclk @200 - REMOTE (fake) UART @24 u_uart_remota.tx_dbg_st[31:0] @28 u_uart_remota.outdat -@24 -u_uart_remota.rx_dbg_st[31:0] -@28 -u_uart_remota.recv[7:0] -@22 -u_uart_remota.recv[7:0] -@200 -- write-back -@28 -u_core.wb_muxc[2:0] -u_core.wb_wreg -@22 -u_core.wb_a_c[4:0] -u_core.wb_c[31:0] +u_uart_remota.tx_clk [pattern_trace] 1 [pattern_trace] 0 diff --git a/cMIPS/v_tx.sav b/cMIPS/v_tx.sav index 261b731..77d368a 100644 --- a/cMIPS/v_tx.sav +++ b/cMIPS/v_tx.sav @@ -1,22 +1,22 @@ [*] [*] GTKWave Analyzer v3.3.37 (w)1999-2012 BSI -[*] Sun May 17 23:22:05 2015 +[*] Tue Mar 28 23:17:37 2017 [*] [dumpfile] "/home/roberto/cMIPS/v_cMIPS.vcd" -[dumpfile_mtime] "Sun May 17 23:20:27 2015" -[dumpfile_size] 22609843 +[dumpfile_mtime] "Tue Mar 28 23:15:02 2017" +[dumpfile_size] 21988875 [savefile] "/home/roberto/cMIPS/v_tx.sav" -[timestart] 1526000000 -[size] 1062 917 -[pos] 676 109 -*-30.000000 2000000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[timestart] 0 +[size] 1062 876 +[pos] 854 8 +*-33.000000 7730600000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] u_core. [treeopen] u_core.u_alu. [treeopen] u_simple_uart. [sst_width] 210 [signals_width] 218 [sst_expanded] 1 -[sst_vpaned_height] 268 +[sst_vpaned_height] 255 @28 clk @22 @@ -27,6 +27,7 @@ u_core.instr_fetched[31:0] @22 u_core.regs_a[31:0] u_core.regs_b[31:0] +u_core.rf_instruction[31:0] @200 - exec @24 @@ -45,11 +46,21 @@ d_addr[31:0] cpu_d_aval u_core.mm_wrmem @22 -u_print_data.data[31:0] +u_core.data_inp[31:0] +u_core.data_out[31:0] @200 -- UART +- write-back @28 +u_core.wb_muxc[2:0] +u_core.wb_wreg +@22 +u_core.wb_a_c[4:0] +u_core.wb_c[31:0] +@200 +- UART +@29 u_simple_uart.u_uart.s_stat +@28 u_simple_uart.u_uart.status[7:0] u_simple_uart.u_uart.s_ctrl u_simple_uart.u_uart.ctrl[7:0] @@ -68,7 +79,7 @@ u_simple_uart.u_uart.tx_dbg_st[31:0] u_simple_uart.u_uart.tx_shr_full u_simple_uart.u_uart.txclk u_simple_uart.u_uart.txdat -@23 +@22 u_interrupt_counter.q[29:0] @200 - REMOTE (fake) UART @@ -78,13 +89,5 @@ u_uart_remota.rx_dbg_st[31:0] u_uart_remota.recv[7:0] @22 u_uart_remota.recv[7:0] -@200 -- write-back -@28 -u_core.wb_muxc[2:0] -u_core.wb_wreg -@22 -u_core.wb_a_c[4:0] -u_core.wb_c[31:0] [pattern_trace] 1 [pattern_trace] 0 diff --git a/cMIPS/vhdl/core.vhd b/cMIPS/vhdl/core.vhd index a5bc888..c4910c4 100644 --- a/cMIPS/vhdl/core.vhd +++ b/cMIPS/vhdl/core.vhd @@ -1407,7 +1407,7 @@ begin addrError <= i_addrError; -- assert mem_excp_type = exNOP -- DEBUG - -- report "SIMULATION ERROR -- data addressing error: " & + -- report LF & "SIMULATION ERROR -- data addressing error: " & -- integer'image(exception_type'pos(mem_excp_type)) & -- " at address: " & SLV32HEX(v_addr) -- severity error; @@ -1422,7 +1422,7 @@ begin -- EX_addr <= v_addr; -- without TLB -- assert ( (phy_d_addr = v_addr) and (EX_aVal = '0') ) -- DEBUG - -- report "mapping mismatch V:P "&SLV32HEX(v_addr)&":"&SLV32HEX(phy_d_addr); + -- report LF&"mapping mismatch V:P "&SLV32HEX(v_addr)&":"&SLV32HEX(phy_d_addr); EX_wreg <= EX_wreg_pre -- movz,movn, move/DO_NOT move @@ -2690,11 +2690,17 @@ begin i_stage_mm := FALSE; i_exception := FALSE; end if; - + + -- uncomment when making use of the TLB TLB_excp_type <= i_excp_type; tlb_stage_MM <= i_stage_mm; tlb_exception <= i_exception and not(SL2BOOL(tlb_ex_2)); - + + -- uncomment when NOT making use of the TLB + -- TLB_excp_type <= exNOP; + -- tlb_stage_MM <= FALSE; + -- tlb_exception <= FALSE; + end process MMU_exceptions; -- ----------------------------------------- -- catch only first exception, if there are two in consecutive cycles -- GitLab