OpenCores
URL https://opencores.org/ocsvn/s6soc/s6soc/trunk

Subversion Repositories s6soc

[/] [s6soc/] [trunk/] [sw/] [zipos/] [resetdump.s] - Rev 45

Compare with Previous | Blame | View Log

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;//
;;
;; Filename: 	resetdump.s
;;
;; Project:	CMod S6 System on a Chip, ZipCPU demonstration project
;;
;; Purpose:	While most of my ZipCPU programs to date have started with a
;;		simple assembly script to load the stack and call the program
;;	entry point, this is different.  This is a very complicated startup
;;	script designed to dump all of the internal information to the CPU
;;	to a UART output port.  This is on purpose.  Indeed, this may be my
;;	only means of debugging the device once it goes bad:
;;
;;	- To set a breakpoint
;;		at the location desired call kpanic(), the CPU will dump its
;;			variables and restart.
;;		sometime before the desired clock, set the watchdog timer
;;			(currently TIMER_B).  When the watchdog expires,
;;			the CPU will restart.  Adjusting the watchdog will
;;			adjust how long the CPU waits before restarting, and
;;			may also adjust what instructions you find going on
;;
;;	- In hardware, you can set the scope.  On boot up, this resetdump
;;		startup will dump the value of the scope to the UART.
;;
;;	Of course, this all depends upon someone listening on the uart.  That's
;;	the purpose of the dumpuart.cpp program in the sw/host directory.
;;	That file will capture the dump so it can be examined later.
;;
;; Creator:	Dan Gisselquist, Ph.D.
;;		Gisselquist Technology, LLC
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;//
;;
;; Copyright (C) 2015-2017, Gisselquist Technology, LLC
;;
;; This program is free software (firmware): you can redistribute it and/or
;; modify it under the terms of  the GNU General Public License as published
;; by the Free Software Foundation, either version 3 of the License, or (at
;; your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
;; for more details.
;;
;; You should have received a copy of the GNU General Public License along
;; with this program.  (It's in the $(ROOT)/doc directory, run make with no
;; target there if the PDF file isn't present.)  If not, see
;; <http://www.gnu.org/licenses/> for a copy.
;;
;; License:	GPL, v3, as defined and found on www.gnu.org,
;;		http://www.gnu.org/licenses/gpl.html
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;//
;;
;;
	.section	.start
	.global		_start
	.type		_start,@function
_start:
; Upon reset, we must output our registers to the UART, lest we reset because
; of a crash
	SW	R0,(DBG)
	JSR	internal_kpanic
	LDI	_top_of_stack,SP
	LDI	kernel_entry,R0
	BRA	_bootloader
 
	.global		kpanic
	.type		kpanic,@function
kpanic:
	SW	R0,(DBG)
	SW	R1,4(DBG)
	SW	R2,8(DBG)
	LDI	panicstr, R1
	JSR	raw_put_string
	LW	4(DBG),R1
	LW	8(DBG),R2
	JSR	internal_kpanic
kpanic_wait_for_button_release:
	LW	(SPIO),R0
	TEST	0x010,R0
	BNZ	kpanic_wait_for_button_release
kpanic_wait_for_button:
	LW	(SPIO),R0
	TEST	0x010,R0
	BZ	kpanic_wait_for_button
	BRA	_start
	HALT
 
internal_kpanic:
	; The original R0 is stored in (DBG)
	SW	R1,4(DBG)
	SW	R2,8(DBG)
	SW	R0,12(DBG)	; Our return address
 
	; R0
	LDI	0,R1
	LW	(DBG),R2
	JSR	uart_put_reg_value
 
	; R1
	LDI	1,R1
	LW	4(DBG),R2
	JSR	uart_put_reg_value
	; R2
	LDI	2,R1
	LW	8(DBG),R2
	JSR	uart_put_reg_value
	; R3
	LDI	3,R1
	MOV	R3,R2
	JSR	uart_put_reg_value
 
	; R4
	LDI	4,R1
	MOV	R4,R2
	JSR	uart_put_reg_value
 
	; R5
	LDI	5,R1
	MOV	R5,R2
	JSR	uart_put_reg_value
 
	; R6
	LDI	6,R1
	MOV	R6,R2
	JSR	uart_put_reg_value
 
	; R7
	LDI	7,R1
	MOV	R7,R2
	JSR	uart_put_reg_value
 
	; R8
	LDI	8,R1
	MOV	R8,R2
	JSR	uart_put_reg_value
 
	; R9
	LDI	9,R1
	MOV	R9,R2
	JSR	uart_put_reg_value
 
	; R10
	LDI	10,R1
	MOV	R10,R2
	JSR	uart_put_reg_value
 
	; R11
	LDI	11,R1
	MOV	R11,R2
	JSR	uart_put_reg_value
 
	; R12
	LDI	12,R1
	MOV	R12,R2
	JSR	uart_put_reg_value
 
	; SP
	LDI	13,R1
	MOV	R13,R2
	JSR	uart_put_reg_value
 
	; uR0
	LDI	16,R1
	MOV	uR0,R2
	JSR	uart_put_reg_value
 
	; uR1
	LDI	17,R1
	MOV	uR1,R2
	JSR	uart_put_reg_value
 
	LDI	18,R1
	MOV	uR2,R2
	JSR	uart_put_reg_value
 
	LDI	19,R1
	MOV	uR3,R2
	JSR	uart_put_reg_value
 
	LDI	20,R1
	MOV	uR4,R2
	JSR	uart_put_reg_value
 
	LDI	21,R1
	MOV	uR5,R2
	JSR	uart_put_reg_value
 
	LDI	22,R1
	MOV	uR6,R2
	JSR	uart_put_reg_value
 
	LDI	23,R1
	MOV	uR7,R2
	JSR	uart_put_reg_value
 
	LDI	24,R1
	MOV	uR8,R2
	JSR	uart_put_reg_value
 
	LDI	25,R1
	MOV	uR9,R2
	JSR	uart_put_reg_value
 
	LDI	26,R1
	MOV	uR10,R2
	JSR	uart_put_reg_value
 
	LDI	27,R1
	MOV	uR11,R2
	JSR	uart_put_reg_value
 
	LDI	28,R1
	MOV	uR12,R2
	JSR	uart_put_reg_value
 
	; uSP
	LDI	29,R1
	MOV	uSP,R2
	JSR	uart_put_reg_value
 
	; uCC
	LDI	30,R1
	MOV	uCC,R2
	JSR	uart_put_reg_value
 
	; uPC
	LDI	31,R1
	MOV	uPC,R2
	JSR	uart_put_reg_value
 
;stack_mem_dump:
;	LDI	0,R4
;	LDI	_top_of_stack,R5
;stack_mem_dump_loop:
;	MOV	R4,R1
;	LW	(R5),R2
;	JSR	uart_put_stack_value
;	ADD	4,R4
;	SUB	4,R5
;	CMP	256,R4
;	BLT	stack_mem_dump_loop
 
; Get prepared for a proper start by setting our stack register
	LDI	_top_of_stack,SP
 
	BRA	dump_scope
	; BRA	end_internal_panic
 
; Now, do a full dump of all memory--all registers are available to us
dump_memory:
	LDI	RAM,R5
	LDI	0x0fff,R6
	LDI	0x0f8,R7
	SW	R7,(SPIO)
full_mem_dump_loop:
	MOV	R5,R1
	LW	(R5),R2
	JSR	uart_dump_mem_value
	LDI	0x0f2,R7
	SW	R7,(SPIO)
 
	ADD	4,R5
	SUB	1,R6
	BGE	full_mem_dump_loop
 
	LDI	0x0f5,R7
	SW	R7,(SPIO)
 
dump_scope:
; Finally, do a full dump of the scope--if it had triggered
;   First, dump the scope control word
	LDI	SCOPE,R7	; R7 = Debugging scope address
	MOV	R7,R1
	LW	(R7),R2
	MOV	R2,R5		; R5 will not be changed by a subroutine
	JSR	uart_dump_mem_value
;   Then test whether or not the scope has stopped
	LDI	0x40000000,R1
	TEST	R1,R5
;   If not, start our kernel.
	BZ	dump_buserr
;   Otherwise, calculate the size of the scope
	LSR	20,R5
	AND	0x1f,R5
	LDI	1,R6
	LSL	R5,R6	; R6 is now the size (number of words) of the scope
	SUB	1,R6	; Now it is one less than the size,2 support the BGE l8r
;   And start dumping
	ADD	4,R7	; Get the scope data address
dump_scope_loop:
	MOV	R7,R1
	LW	(R7),R2
	JSR	uart_dump_mem_value
	SUB	1,R6
	BGE	dump_scope_loop
 
dump_buserr:
; Dump a bus error address, if used
	LDI	buserr_header, R1
	JSR	raw_put_string
	LDI	BUSERR,R1
	LW	(R1),R2
	JSR	uart_dump_mem_value
 
end_internal_panic:
	LDI	doublenewline,R1
	JSR	raw_put_string
	LDI	0x0ff,R7
	SW	R7,(SPIO)
	LW	12(DBG),PC
	JMP	R0
 
; R0 is return address
; R1 is register ID
; R2 is register value to output
uart_put_reg_value:
	SW	R0,16(DBG)
	SW	R2,20(DBG)
	SW	R3,24(DBG)
	MOV	R1,R2
	LDI	'u',R1
	CMP	16,R2
	LDILO.LT 's',R1
	SUB.GE	16,R2
	JSR	raw_put_uart
	LDI	'0',R1
	CMP	10,R2
	LDILO.GE '1',R1
	SUB.GE	10,R2
	JSR	raw_put_uart
	MOV	R2,R1
	AND	15,R1
	JSR	get_hex
	JSR	raw_put_uart
	LDI	':',R1
	JSR	raw_put_uart
	LW	20(DBG),R2
	LDI	8,R3
uart_put_loop:
	MOV	R2,R1
	LSR	28,R1
	LSL	4,R2
	JSR	get_hex
	JSR	raw_put_uart
	SUB	1,R3
	BNZ	uart_put_loop
	LDI	newline, R1
	JSR	raw_put_string
	LW	16(DBG),R0
	LW	20(DBG),R2
	LW	24(DBG),R3
	JMP	R0
 
uart_dump_mem_value:
;	R0 = return address
;	R1 = Memory address
;	R2 = Memory Value
; Local: R3 = working value
	SW	R0,28(DBG)
	MOV	R1,R3		; R3 = Memory address
	MOV	R2,R4		; R4 = Memory Value
	LDI	memopenstr,R1
	JSR	raw_put_string
	; Set up a loop to dump things
	LSL	16,R3		; Ignore the first 16 bits
	LDI	4,R2		; We're going to do four hex digits here
	;
uart_put_mem_address_loop:
	MOV	R3,R1
	LSR	28,R1
	LSL	4,R3
	JSR	get_hex
	JSR	raw_put_uart
	SUB	1,R2
	BNZ	uart_put_mem_address_loop
	; Put some transition characters
	LDI	memmidstr,R1
	JSR	raw_put_string
 
	; Set up a loop to dump the memory value now
	LDI	8,R2
uart_put_mem_value_loop:
	MOV	R4,R1
	LSR	28,R1
	LSL	4,R4
	JSR	get_hex
	JSR	raw_put_uart
	SUB	1,R2
	BNZ	uart_put_mem_value_loop
	; Clear the line
	LDI	newline,R1
	JSR	raw_put_string
	; And return from our subroutine
	LW	28(DBG),R0
	JMP	R0
 
get_hex:
	ADD	0x30,R1
	CMP	0x3a,R1
	ADD.GE	7,R1	; Add 'A'-'0'-10
	JMP	R0
 
; R0 is the return address
; R1 is the string address
raw_put_string:
	SW	R0,36(DBG)
	SW	R2,40(DBG)
	MOV	R1,R2
raw_put_string_next:
	LB	(R2),R1
	CMP	0,R1
	LW.Z	36(DBG),R0
	LW.Z	40(DBG),R2
	RTN.Z
	ADD	1,R2
	MOV	raw_put_string_next(PC),R0
	BRA	raw_put_uart
 
; R0 is return address,
; R1 is value to transmit
raw_put_uart:
	SW	R2,32(DBG)
	LDI	INT_UARTTX,R2
	SW	R2,(PIC)	; Clear the PIC, turn off interrupts, etc.
raw_put_uart_retest:
	LW	(PIC),R2
	TEST	INT_UARTTX,R2
	BZ	raw_put_uart_retest
	SW	R1,(UART)
	LW	32(DBG),R2
	JMP	R0
 
	.section	.fixdata
DBG:
.int	0,0,0,0,0,0,0,0,0,0
 
.set	INT_UARTRX, 0x040
.set	INT_UARTTX, 0x080
.set	PIC,     0x0400
.set	BUSERR,  0x0404
.set	TMRA,    0x0408
.set	TMRB,    0x040c
.set	PWM,     0x0410
.set	SPIO,    0x0414
.set	GPIO,    0x0418
.set	UART,    0x041c
.set	VERSION, 0x0420
.set	SCOPE,   0x0800
.set	SCOPED,  0x0804
.set	RAM,     0x8000
	.section	.rodata
doublenewline:
	.ascii	"\r\n"
newline:
	.asciz	"\r\n"
buserr_header:
	.string	"BusErr: "
panicstr:
	.string	"Panic: \r\n"
memopenstr:
	.string	"M[0x"
memmidstr:
	.string	"]; "
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.