Building a DSP board, Part Seven: Serial Loader Bootstrap
This is the seventh in a series on how I went about building a dual Motorola DSP56000 sampling board.
Okay, first off, how did I make this board two channel in, four channel out? Well, I told you how to make a single DSP board (two in, two out). All you have to do is hook the second DSP to same input section you made for the first one, and make another completely new output section for the second one.
Now we have to make the board boot. Since I'm using two DSPs, I'll have to burn two EPROMs. First, let's find out how the built-in bootstrap ROM on the 56000 works.
When the 56000 boots, it loads its original operating mode from some external pins. There are four different modes. We want to set the chip up for a mode 1 initialization. Mode 1 loads an external program into internal program RAM (PRAM) and then switches to mode 2 and starts executing from internal PRAM. Mode 2 is the standard operating mode. Mode 1 is a fairly whacked out operating mode. The 56000 executes from internal PROM, reads from external PROM, and then writes to internal PRAM.
The first thing the 56000 does is decide whether to load from an external byte-wide PROM or load from the byte-wide host port. It does this by checking the MSBit of P:$C000 (the P: prefix means a reference to the program memory, as opposed to the X: and Y: memories). We set this bit high (we want it to boot from EPROM) by tying D23 to +5V through a 10k resistor. The 56000 then selects 15 wait states (more than enough for our slow 250ns EPROM) and begins loading the PRAM from the EPROM.
Now, how does the 56000 map 8 bit-wide bytes into 24 bit-wide words? Let's have a look:
EPROM PRAM
$C000 $0000 low byte
$C001 $0000 middle byte
$C002 $0000 high byte
. .
$C5FD $01FF low byte
$C5FE $01FF middle byte
$C5FF $01FF high byte
Note that the PRAM loading is the Intel bassackwards method of LSB MSB instead of the awesome Motorola method of MSB LSB. Go figure...
Now, I didn't feel like dealing with the $C000 decoding, so I just hooked up the lower address bits to the EPROM (I used a 2716) plus the P address bank selector.
So, after the 56000 is done loading from the EPROM, it switches to operating mode 2 (maps PRAM to program fetching as well as P: writing) and boots the program it just loaded from P:$0000.
Here is the program that I blasted into my EPROM. I think it is documented fairly okay, so I won't say anything else.
Next time: initializing all of your hardware
---------------------------------------------------------------------
; sloader.asm
; Wed Aug 2 23:56:14 PDT 1989
; This file originally came from Motorola's Dr. BuB DSP board.
; Slightly modified by Todd Day (todd@ivucsb.sba.ca.us)
; to echo characters received.
; Serial Loader for the DSP56000.
; This loader initializes the serial communications interface (SCI)
; on the DSP56001 for 9600 baud and then loads OMF records (output
; by the DSP56000 assembler) into internal memory. The loader takes
; the upper 128 bytes of P memory allowing the lower memory from
; $0000-(LDRMEM-1) to be used by the user. The following records are
; interpreted:
; _DATA X ADDR
; _DATA Y ADDR
; _DATA P ADDR
; _END ADDR
; After the END record is encountered, the loader jumps to the address
; in the END record. Note that an address MUST be present in the
; END record (the program must contain at least one P segment).
;
; To generate a EPROM of this loader (8Kx8), perform the following:
; $ asm56000 -b -l -a sloader
; $ srec sloader
;
; The EPROM is in file SLOADER.P. To program the EPROM, set the
; programmer to MOTOROLA S record format, download the file with
; a zero address offset and program the part.
;
; BTW, S record format is LSB MidSB MSB (what! Intel format? :-)
; Took me a few hours to figure this one out!
;
; If you don't have the program srec (where can I get this?),
; you have to do some gnarly contortions on the .LOD file.
;
; So, if your .LOD file resulting from compiling this program
; looks like this:
;
; _START SLOADER 0000 0000
;
; _DATA P 0020
; 010203 040506 070809
; _END 0020
;
; then, program your PROM with this sequence:
; $0020 0302 0106 0504 0908 07..... etc. (Fun, eh? :)
;
;
; The loader loads the following memory spaces:
; X - 0 to FF
; Y - 0 to FF
; P - 0 to LDRMEM-1
;
PAGE 68,66,1,1
SCR EQU $FFF0 ;SCI CONTROL REGISTER
SCCR EQU $FFF2 ;SCI CLOCK CONTROL REGISTER
PCC EQU $FFE1 ;PORT C CONTROL REGISTER
RDRF EQU $2 ;RECEIVE DATA REGISTER FULL FLAG
SSR EQU $FFF1 ;SCI STATUS REGISTER
SRXH EQU $FFF6 ;SCI RECEIVE IN HIGH BYTE
LDRMEM EQU $19D ;START OF LOADER IN P MEMORY
ORG P:$0000 ;RESET VECTOR FOR BOOTING
RVEC
JMP LOAD ;GO EXECUTE LOADER
ORG P:LDRMEM,P:3*LDRMEM
LOAD
MOVEP #$0302,X:SCR ;ENABLE TX,RX: 8 BIT 1 START, 1 STOP
; *** You will probably have to
; *** change the line below!
MOVEP #$0020,X:SCCR ;CD=32 (/33), INT CLK @ 9600 BAUD
MOVEP #$0007,X:PCC ;ENABLE SCI
WTUS
JSR GETCH ;INPUT CHARACTER
MOVE #'_',X0 ;GET UNDERSCORE CHARACTER
CMP X0,A ;SEE IF "_" YET
JNE WTUS ;NO
GOTUS
JSR GETCH ;GET A CHARACTER
MOVE #'D',X0 ;GET A D FOR DATA
CMP X0,A #'E',X0 ;COMPARE TO D, GET E
JEQ DATAREC ;IF "D", THEN DATA RECORD
CMP X0,A ;SEE IF END RECORD
JNE WTUS ;NO, GO WAIT FOR ANOTHER UNDERSCORE
_WTSPC
JSR GETCH ;GET CHARACTER
MOVE #$20,X0 ;GET SPACE
CMP X0,A ;WAIT FOR SPACE AFTER "END"
JNE _WTSPC ;WAIT FOR SPACE
JSR IN4 ;GET TRANSFER ADDRESS
MOVE B1,R0 ;MOVE TRANSFER ADDRESS
NOP ;CLEAR ADDRESS PIPE
JMP (R0) ;GO EXECUTE USER CODE
DATAREC
JSR GETCH ;GET CHARACTER
MOVE #$20,X0 ;GET SPACE
CMP X0,A ;SEE IF SPACE
JNE DATAREC ;NO
JSR GETCH ;GET [P,X,Y]
MOVE A1,Y0 ;SAVE CHARACTER
JSR IN4 ;GET ADDRESS OF DATA RECORD
MOVE B1,R0 ;SAVE ADDRESS
MOVE #'X',A ;GET X
CMP Y0,A #'Y',A ;SEE IF X, GET Y
JEQ _LDX ;LOAD DATA INTO X MEMORY
CMP Y0,A ;SEE IF Y
JEQ _LDY ;LOAD DATA INTO Y MEMORY
_LDP
JSR IN6 ;GET DATA
MOVE B1,P:(R0)+ ;LOAD P MEMORY
JMP _LDP
_LDX
JSR IN4 ;GET DATA
MOVE B1,X:(R0)+ ;LOAD X MEMORY
JMP _LDX
_LDY
JSR IN4 ;GET DATA
MOVE B1,Y:(R0)+ ;LOAD Y MEMORY
JMP _LDY
GETCH
JCLR #RDRF,X:SSR,* ;WAIT FOR DATA IN SCI
MOVEP X:SRXH,A ;GET SCI DATA IN HIGH BYTE
LSL A ;SHIFT OUT PARITY
LSR A ;PUT 0 IN PARITY BIT
MOVE A1,A ;SIGN EXTEND AND ZERO
MOVEP A,X:SRXH ;put sci data in high byte
RTS
IN4
CLR B #>4,X0 ;CLEAR VALUE, GET 4
JMP READHEX ;READ 4 HEX CHARACTERS
IN6
CLR B #>6,X0 ;CLEAR VALUE, GET 6
READHEX
DO X0,_READHEX ;READ ASCII HEX AND CONVERT TO BINARY
_GET
JSR GETCH ;GET A CHARACTER
MOVE #'_',X0 ;GET UNDERSCORE
CMP X0,A #'F',X0 ;SEE IF UNDERSCORE
JNE _NOTUS ;NO
ENDDO ;EXIT LOOP
MOVE SSH,X0 ;POP RETURN ADDRESS
JMP GOTUS ;GO PROCESS NEW INPUT RECORD
_NOTUS
CMP X0,A #'0',X0 ;SEE IF GREATER THAN F
JGT _GET ;YES, IGNORE
CMP X0,A ;SEE IF LESS THAN 0
JLT _GET ;YES, IGNORE
SUB X0,A #10,X0 ;ADJUST FOR ASCII TO BINARY
CMP X0,A #7,X0 ;SEE IF A-F
JLT _NOTALPHA ;NO
SUB X0,A ;ADJUST FOR 1-F
_NOTALPHA
REP #4 ;SHIFT OLD VALUE LEFT 1 NIBBLE
LSL B
REP #16 ;SHIFT NEW NIBBLE DOWN TO LSB
LSR A
ADD A,B ;ADD NEW NIBBLE IN
_READHEX
RTS
END