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

Subversion Repositories s6soc

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

Go to most recent revision | 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-2016, 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
	STO	R0,(DBG)
	MOV	PC+1,R0
	BRA	internal_kpanic
	LDI	_top_of_stack,SP
	LDI	kernel_entry,R0
	BRA	bootloader
 
	.global		kpanic
	.type		kpanic,@function
kpanic:
	STO	R0,(DBG)
	STO	R1,1(DBG)
	STO	R2,2(DBG)
	LDI	'P',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'a',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'n',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'i',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'c',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	':',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	' ',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'\r',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'\n',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LOD	1(DBG),R1
	LOD	2(DBG),R2
	MOV	PC+1,R0
	JMP	internal_kpanic
kpanic_wait_for_button_release:
	LOD	(SPIO),R0
	TEST	0x010,R0
	BNZ	kpanic_wait_for_button_release
kpanic_wait_for_button:
	LOD	(SPIO),R0
	TEST	0x010,R0
	BZ	kpanic_wait_for_button
	BRA	_start
	HALT
 
internal_kpanic:
	STO	R1,1(DBG)
	STO	R2,2(DBG)
	STO	R0,3(DBG)	; Our return address
 
	; R0
	LDI	0,R1
	LOD	(DBG),R2
	MOV	.Lcall0(PC),R0
	JMP	uart_put_reg_value
.Lcall0:
 
	; R1
	LDI	1,R1
	LOD	1(DBG),R2
	MOV	.Lcall1(PC),R0
	JMP	uart_put_reg_value
.Lcall1:
	; R2
	LDI	2,R1
	LOD	2(DBG),R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
	; R3
	LDI	3,R1
	MOV	R3,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R4
	LDI	4,R1
	MOV	R4,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R5
	LDI	5,R1
	MOV	R5,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R6
	LDI	6,R1
	MOV	R6,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R7
	LDI	7,R1
	MOV	R7,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R8
	LDI	8,R1
	MOV	R8,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R9
	LDI	9,R1
	MOV	R9,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R10
	LDI	10,R1
	MOV	R10,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R11
	LDI	11,R1
	MOV	R11,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; R12
	LDI	12,R1
	MOV	R12,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; SP
	LDI	13,R1
	MOV	R13,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; uR0
	LDI	16,R1
	MOV	uR0,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; uR1
	LDI	17,R1
	MOV	uR1,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	18,R1
	MOV	uR2,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	19,R1
	MOV	uR3,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	20,R1
	MOV	uR4,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	21,R1
	MOV	uR5,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	22,R1
	MOV	uR6,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	23,R1
	MOV	uR7,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	24,R1
	MOV	uR8,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	25,R1
	MOV	uR9,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	26,R1
	MOV	uR10,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	27,R1
	MOV	uR11,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	LDI	28,R1
	MOV	uR12,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; uSP
	LDI	29,R1
	MOV	uSP,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; uCC
	LDI	30,R1
	MOV	uCC,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
	; uPC
	LDI	31,R1
	MOV	uPC,R2
	MOV	PC+1,R0
	JMP	uart_put_reg_value
 
;stack_mem_dump:
	;LDI	0,R4
	;LDI	_top_of_stack,R5
;stack_mem_dump_loop:
	;MOV	R4,R1
	;LOD	(R5),R2
	;MOV	PC+1,R0
	;JMP	uart_put_stack_value
	;ADD	1,R4
	;SUB	1,R5
	;CMP	64,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	0x1000,R6
	LDI	0x0f8,R7
	STO	R7,(SPIO)
full_mem_dump_loop:
	MOV	R5,R1
	LOD	(R5),R2
	MOV	PC+1,R0
	JMP	uart_dump_mem_value
	LDI	0x0f2,R7
	STO	R7,(SPIO)
 
	ADD	1,R5
	SUB	1,R6
	BGT	full_mem_dump_loop
 
	LDI	0x0f5,R7
	STO	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
	LOD	(R7),R2
	MOV	R2,R5		; R5 will not be changed by a subroutine
	MOV	PC+1,R0
	BRA	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
;   And start dumping
	ADD	1,R7	; Get the scope data address
dump_scope_loop:
	MOV	R7,R1
	LOD	(R7),R2
	MOV	PC+1,R0
	BRA	uart_dump_mem_value
	SUB	1,R6
	BGT	dump_scope_loop
 
dump_buserr:
; Dump a bus error address, if used
	LDI	'B',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	'u',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	's',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	'E',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	'r',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	'r',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	':',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	' ',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	BUSERR,R1
	LOD	(R1),R2
	MOV	PC+1,R0
	BRA	uart_dump_mem_value
 
end_internal_panic:
	LDI	'\r',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	'\n',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	'\r',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	'\n',R1
	MOV	PC+1,R0
	BRA	raw_put_uart
	LDI	0x0ff,R7
	STO	R7,(SPIO)
	LOD	3(DBG),PC
	JMP	R0
 
; R0 is return address
; R1 is register ID
; R2 is register to output
uart_put_reg_value:
	STO	R0,4(DBG)
	STO	R2,5(DBG)
	STO	R3,6(DBG)
	MOV	R1,R2
	LDI	'u',R1
	CMP	16,R2
	LDILO.LT 's',R1
	SUB.GE	16,R2
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'0',R1
	CMP	10,R2
	LDILO.GE '1',R1
	SUB.GE	10,R2
	MOV	PC+1,R0
	JMP	raw_put_uart
	MOV	R2,R1
	AND	15,R1
	MOV	PC+1,R0
	JMP	get_hex
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	58,R1	; A ':'
	MOV	PC+1,R0
	JMP	raw_put_uart
	LOD	5(DBG),R2
	LDI	8,R3
uart_put_loop:
	ROL	4,R2
	MOV	R2,R1
	AND	15,R1
	MOV	PC+1,R0
	JMP	get_hex
	MOV	PC+1,R0
	JMP	raw_put_uart
	SUB	1,R3
	BNZ	uart_put_loop
	LDI	'\r',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'\n',R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LOD	4(DBG),R0
	LOD	5(DBG),R2
	LOD	6(DBG),R3
	JMP	R0
 
uart_dump_mem_value:
;	R0 = return address
;	R1 = Memory address
;	R2 = Memory Value
; Local: R3 = working value
	STO	R0,7(DBG)
	MOV	R1,R3		; R3 = Memory address
	MOV	R2,R4		; R4 = Memory Value
	LDI	77,R1		; 77 = 'M'
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	91,R1		; 91 = '['
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	48,R1		; A '0'
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	120,R1		; An 'x'
	MOV	PC+1,R0
	JMP	raw_put_uart
	; Set up a loop to dump things
	ROL	16,R3		; Ignore the first 16 bits
	LDI	4,R2		; We're going to do four hex digits here
	;
uart_put_mem_address_loop:
	ROL	4,R3
	MOV	R3,R1
	AND	15,R1
	MOV	PC+1,R0
	JMP	get_hex
	MOV	PC+1,R0
	JMP	raw_put_uart
	SUB	1,R2
	BNZ	uart_put_mem_address_loop
	; Put some transition characters
	LDI	93,R1		; 93 = ']'
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	58, R1		; A semicolon
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	32, R1		; A space
	MOV	PC+1,R0
	JMP	raw_put_uart
 
	; Set up a loop to dump the memory value now
	LDI	8,R2
uart_put_mem_value_loop:
	ROL	4,R4
	MOV	R4,R1
	AND	15,R1
	MOV	PC+1,R0
	JMP	get_hex
	MOV	PC+1,R0
	JMP	raw_put_uart
	SUB	1,R2
	BNZ	uart_put_mem_value_loop
	; Clear the line
	LDI	'\r', R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	LDI	'\n', R1
	MOV	PC+1,R0
	JMP	raw_put_uart
	; And return from our subroutine
	LOD	7(DBG),R0
	JMP	R0
 
get_hex:
	ADD	0x30,R1
	CMP	0x39,R1
	ADD.GT	7,R1	; Add 'A'-'0'-10
	JMP	R0
 
raw_put_uart:	; R0 is return address, R1 is value to transmit
	STO	R2,8(DBG)
	LDI	INT_UARTTX,R2
	STO	R2,(PIC)	; Clear the PIC, turn off interrupts, etc.
raw_put_uart_retest:
	LOD	(PIC),R2
	TEST	INT_UARTTX,R2
	BZ	raw_put_uart_retest
	STO	R1,(UART)
	LOD	8(DBG),R2
	JMP	R0
 
	.section	.fixdata
DBG:
.byte	0,0,0,0,0,0,0,0,0
 
.set	INT_UARTRX, 0x040
.set	INT_UARTTX, 0x080
.set	PIC,     0x0100
.set	BUSERR,  0x0101
.set	TMRA,    0x0102
.set	TMRB,    0x0103
.set	PWM,     0x0104
.set	SPIO,    0x0105
.set	GPIO,    0x0106
.set	UART,    0x0107
.set	VERSION, 0x0108
.set	SCOPE,   0x0200
.set	SCOPED,  0x0201
.set	CLOCK,   0x0800
.set	CONFIG,  0x0400
.set	TIMER,   0x0801
.set	STOPWATCH,0x802
.set	ALARM,   0x0803
.set	RAM,     0x2000
 

Go to most recent revision | 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.