subttl '(c) 1981 Morrow Designs' title 'MPZ-80 MON4.47 FIRMWARE' .z80 aseg ;**************************************************************** ;* * ;* Decision one CPU firmware, for the Morrow Designs / Thinker * ;* Toys Decision one computer. The monitor routine looks for * ;* the power on jump addresses on CPU switches which determine * ;* address to begin execution (top 5 switches). I/O is through * ;* the Wunderbus I/O motherboard UART 1. Base address of the * ;* I/O is assumed to be standard (beginning at port 48H). * ;* If top five switches are 'On', a hard disk is assumed to be * ;* the disk device and Boothd is executed. * ;* * ;* Revised 3/24/82 - Restore maps before power on * ;* jump with switch 6 off for cold * ;* boot of MOS. * ;* * ;* Revised 12/28/82 - Fixed PIC init routine * ;* * ;* Revised 11/15/82 - added nop to wrtask for correct * ;* delay count * ;* * ;* Revised 8/27/82 - M16 home and load constants * ;* changed. group0-3 equates now * ;* set int en bit high. * ;* * ;* Bobby Dale Gifford and Bob Groppo * ;* 10/20/81 * ;* * ;**************************************************************** org 0 ;Local Ram in task zero tempstk equ 0200h ;temporary stack nop equ 0 gobuff equ 01b0h ;location of task switch routine on 'RESET' jmpop equ 0c3h ;Jump unstruction op-code callop equ 0cdh ;z80 call instruction opcode t1mask equ 2bh ;unlimited mask... no traps enabled t0mask equ 2bh ;unlimited mask ssmode equ 036h ;single step mode mask hstrap equ 1Ah ;allow traps on halts and stops, interrupts ;- masked out in task 0 (temporary) window equ 01h ;task 0 window at location 10000 ACR equ 0Dh ;carriage return ALF equ 0Ah ;line feed ASP equ ' ' ;space AFF equ 0Ch ;form feed BEl equ 07H ;bell BSP equ 08H ;backspace mskofst equ 19h ;offset to get to user's mask reg. contents spofst equ 17h ;offset to stack pointer of user afofst equ 15h ;offset to user Af register hlofst equ 13h ;offset to user h,l register deofst equ 11h ;offset to d,e bcofst equ 0Fh ;offset to b,c pcofst equ 0Dh ;offset to the users pc register nxtbyte equ 076h ;byte after a halt ersav equ regsav + 2 ;temporary error save area ;**************************************************************** ;* * ;* Wunderbus I/O equates: * ;* * ;**************************************************************** base equ 048h ;I/O base address of wunderbus ports group0 equ 08h group1 equ 09h ;serial port 1 group2 equ 0ah ;serial port 2 Šgroup3 equ 0bh ;serial port 3 grpctl equ base+7 ;I/O group select port ; UART equates dll equ base ;divisor latch lsb dlm equ base+1 ;divisor latch msb ier equ base+1 ;interupt enable register lcr equ base+3 ;line control register mcr equ base+4 ;modem control register lsr equ base+5 ;line status register rbr equ base ;read data buffer thr equ base ;transmitter data buffer dlab equ 80h ;divisor latch access bit thre equ 20h ;status line TBE dr equ 01 ;line status DR bit wls0 equ 01 ;word length select bit 0 wls1 equ 02 ;word length select bit 1 (for 8 bit word) stb equ 04 ;stop bit count (2 stop bits) imask equ 00 ;non interupt mode loop equ 010h ;UART loop mode ; PIC equates init equ 010h ;bit high to initialize the PIC icw1 equ base + 4 ;PIC initialization control word 1 icw2 equ base + 5 ;PIC initialization control word 2 icw3 equ base + 5 ;PIC initialization control word 3 icw4 equ base + 5 ;PIC initialization control word 4 ocw1 equ base + 5 ;PIC interrupt mask register ocw2 equ base + 4 ;PIC EOI register picmask equ 0ffh ;mask to turn all interrupts off ltim equ 018h ;ICW access + level triggered mode adi4 equ 04h ;call address intervals = 4 adi8 equ 00h ;call address intervals = 8 sngl equ 02 ;sole system PIC ic4 equ 01h ;icw4 access bit lovect equ 0 ;call vectors begin at 0 hivect equ 0 ;call vectors begin at 0 normal equ 0ch ;Master/Reg. nest/buffered/no AEOI/8085 ; -normal setting of OCW4 for Morrow Software eoi equ 20h ;non-specific EOI constant ivalu equ init OR ltim OR adi4 OR sngl OR ic4 OR lovect ;**************************************************************** ;* * ;* HDC Winchester controller equates * ;* * ;**************************************************************** revnum equ 13 ioaddr equ 120Q contrl equ ioaddr status equ ioaddr data equ ioaddr+3 functn equ ioaddr+2 commd equ ioaddr+1 Šsecstat equ ioaddr+1 dread equ 1 sector equ 1 opdone equ 2 complt equ 4 header equ 10Q drenbl equ 5 dskrun equ 7 ready equ 40Q system equ 200Q stepo equ 370Q drivea equ 374Q trk0 equ 1 ;**************************************************************** ;* * ;* DJ-DMA Equates * ;* * ;**************************************************************** djstat equ 104ah ;adjusted channel address of status byte ;**************************************************************** ;* * ;* DMA Winchester Controller Equates * ;* * ;**************************************************************** cyl equ 153 ;number cylinders for Seagate ST-506 heads equ 4 ;number heads for Seagate ST-506 stpdly equ 01eh ;15 msec for Seagate ST-506 hdsetl equ 0C8h ;20 msec for Seagate ST-506 secsiz equ 3 ;512 byte sectors for Micronix readat equ 0 ;DMA controller read sector opcode write equ 1 ;DMA controller write sector opcode rhead equ 2 ;DMA controller read header opcode format equ 3 ;DMA controller format track opcode const equ 4 ;load drive constants command sense equ 5 ;return drive status command noop equ 6 ;command used when seeking dmarst equ 54h ;DMA controller reset port attn equ 55h ;DMA controller Attention port stepout equ 10h ;Step direction to track 0 stepin equ 0 ;Step direction away from track 0 track0 equ 1 ;track 0 status wfault equ 2 ;write fault condition from drive dready equ 4 ;drive ready status sekcmp equ 8 ;seek complete status hdspt equ 17 ;number of sectors per track iopb equ 1050h ;pointer to the channel chan equ 1080h ;actual channel select equ chan + 3 ;select byte in channel dmaddr equ chan + 4 ;24 bit dma address location arg equ chan + 7 ;beginning of four arguments to commands cmmd equ chan + 11 ;actual command location statis equ chan + 12 ;controller return status location Šlink equ chan + 13 ;link field address for next command bootad equ 1100h ;dma address for first sector from hddma good equ 0ffh ;good status result ;**************************************************************** ;* * ;* Decision One Ram variables, visible only to task 0. * ;* * ;**************************************************************** ram equ $ ;Local RAM, visible only to task 0 ;**************************************************************** ;* * ;* Supervisor entry point, this jump must be inserted into the * ;* CPU's ram by the supervisor for subsequent entry to the * ;* supervisor when traps occur. * ;* * ;**************************************************************** super: jp super ;Supervisor entry point Šuser: jp user ;(7) User entry point ctask: db 0 ;Current task cmask: db 0 ;Current mask contents cstack: dw 0 ;temporary save stack u.sp: dw 0 u.pc: dw 0 u.de: dw 0 u.hl: dw 0 u.af: dw 0 begsav equ $ regsav: dw 0 ;address of beginning of reg save area ds 1Ch monstk equ $ ;monitor stack area ds (200h - 01eh) - monstk ;******************************************************** ;* * ;* Initialized stack at 200h contents * ;* * ;******************************************************** retstk: dw 0 ;return address from call to monitor or super tskmsk: dw 0 t.pc: dw 0 t.sp: dw 0 ;users stack pointer t.af: dw 0 ;primary A & f register save t.bc: dw 0 ;primary b & c register save t.de: dw 0 ;primary d & e register save t.hl: dw 0 ;primary h & l register save t.int: dw 0 ;interrupt register register save t.ix: dw 0 ; ix register save t.iy: dw 0 ; iy register save t.af1: dw 0 ; alternate A & f register save t.bc1: dw 0 ; alternate b & c register save t.de1: dw 0 ; alternate d & e register save t.hl1: dw 0 ; alternate h & l register save ;**************************************************************** ;* * ;* The following map is used to hold an image of the current * ;* memory map for all tasks. * ;* * ;**************************************************************** map: ds 200h ;Task Memory map image ;**************************************************************** ;* * ;* Decision One local I/O map, the following registers are * ;* memory mapped into task 0, and are always visible to task * ;* zero only. * ;* * ;**************************************************************** locio equ $ ;Local I/O, visible only to task 0 trpadd: ds 0 ;Trapp address register (read) dspseg: ds 1 ;Display segment register (write) keybd: ds 0 ;Key board register (read) dspcol: ds 1 ;Display column register (write) switch: ds 0 ;CPU switch port (read) task: ds 1 ;Task register (write) stats: ds 0 ;Trap status register (read) mask: ds 1 ;Task mask register (write) elocio equ $ ;End of local I/O ds 200h-(elocio-locio) ;Fill out local I/O ;**************************************************************** ;* * ;* The following ram is the actual memory map, it can only be * ;* written into, so an image is kept in the local ram. * ;* * ;**************************************************************** mapram: ds 200h ;Memory Map RAM, visible only to task 0 ;**************************************************************** ;* * ;* Decision One prom routines, usable by the supervisor task * ;* but not accessible by any other tasks. * ;* * ;**************************************************************** rom0 equ $ ;Local ROM, visible only to task 0 ;and is visible only during RESET ;**************************************************************** ;* * ;* Reset is executed only once. Currently, reset forms an * ;* identity map for task zero to occupy the first 64K of main * ;* memory, allows task 0 to have unlimited priviledges. Task1 * ;* occupies the first 64K, unlimited access and the traps are * ;* set for halts or a stop. All other task maps are initialized * ;* starting at bank 2 to bank 15. (e.g. task 15 has bank 15). * ;* If swithches are set with S1 through S7 off and S8 on, the * ;* power on jump address will be F800. If switch 6 is on, the * ;* program will jump to the monitor regardless of the state * ;* of the other switches. If S1 - S5 are all 'ON' a MORROW * ;* hard disk is assumed and the 'Boothd' program is executed. * ;* If pin 13 of 12C is grounded, the diagnostic mode is entered.* ;* * ;**************************************************************** ; Check all the readable registers regrd: out (0ffh),a ;sync ld hl,trpadd ld a,(hl) ;read trap address reg @ 400h inc hl ld a,(hl) ;read keyboard reg @ 401h inc hl ld a,(hl) ;read switch reg @ 402h inc hl ld a,(hl) ;read trap status reg @ 403h jr getsw Š; Check all the writable registers regwr: xor a ;loop till switch not 00 regwr1: out (0ffh),a ;sync ld (mask),a ;write to the mask register ld (dspcol),a ;write to the display column register ld (dspseg),a ;write to the display segment reg. cpl cp 0ffh jr z,regwr1 jr getsw ; Check the Map RAMs tmap: xor a ;write to map ram / protection ram ld hl,mapram out (0ffh),a ;sync ld (hl),a ;write location 600,0 inc hl ld (hl),a ;write 601,0 cpl ld (hl),a ;write 601,0ffh dec hl ld (hl),a ;write 600,0ffh ld hl,mapram + 01feh ld (hl),a ;write 7fe,0ff inc hl ld (hl),a ;write 7ff,0ff cpl ld (hl),a ;write 7ff,00 dec hl ld (hl),a ;write 7fe,00 jr getsw ; Check the R/W RAMs tram: ld hl,0000h ;write to read/write ram out (0ffh),a tram1: xor a ld (hl),a ;write a 00 to ram cp (hl) ;read it back cpl ld (hl),a ;write an ffh to ram cp (hl) ;read it back bit 0,h jr nz,getsw ld hl,03ffh jr tram1 ;write to 3ffh a ffh ; Check the Floating Point Processor Š tfpp: xor a ;check FPP out (0ffh),a ;sync ld (0c00h),a ;write a 00 to location C00h ld a,(0c00h) ;read c00h getsw: ld a,(keybd) bit 1,a reset: jp z,reset0 ;go to the montior if low ld a,(switch) bit 2,a jp z,reset0 ;go to the monitor if S6 is on and 070h ;strip insignificant bits rrc a ;4 byte offset rrc a ld hl,jtable ;point to beginning of table add a,l ld l,a jp (hl) ; Check the S-100 bus addr and data lines tbus: ld hl,task ld a,0f0h ld (hl),a ;force upper task bits high ld a,0ffh ;init the T0 map ld (61eh),a ld a,03 ld (61fh),a ld (603h),a xor a ld (602h),a out (0ffh),a ;sync ld (0ffffh),a ;write - bus addresses A0-23 are high ld (hl),a ;upper task bits low ld (1000h),a ;write - bus addresses A0-23 are low or 0f0h ld (hl),a ;force upper task bits high ld a,(0ffffh) ;read - bus addresses A0-23 are high xor a ld (hl),a ;force upper task bits low ld a,(1000h) ;read - bus addresses A0-23 are low jr getsw ntbus: ld hl,task ld a,0A0h ld (hl),a ;force upper task bits high ld a,0aah ;init the T0 map ld (61eh),a ld a,03 ld (61fh),a ld (603h),a ld a,55h Š ld (602h),a out (0ffh),a ;sync cpl ld (0faaah),a ;write - bus addresses A0-23 = AAAAAA ld a,50h ld (hl),a ;upper task bits low = 5 or 05h ld (1555h),a ;write - bus addresses A0-23 are low ld a,0A0h ld (hl),a ;force upper task bits high ld a,(0faaah) ;read - bus addresses A0-23 are high ld a,050h ld (hl),a ;force upper task bits low ld a,(1555h) ;read - bus addresses A0-23 are low jp getsw ; Initialize the maps and jump vectors reset0: call reset1 call uartst call setup jp gobuff reset1: ld hl,super ;initialize 'super' to the monitor... settle: dec hl ;wait for hardware to settle down ld a,l or h jr nz,settle ld (hl),jmpop ;- this will be overwritten by the inc hl ;- supervisor but all traps in the ld (hl),00h ;- meantime will fall into the monitor. inc hl ld (hl),10h ld hl,map ld (cstack),hl ;initialize a temporary stack reslop: xor a ld c,3 ;New access priviledges reslp2: ld b,a ;New allocation = segment # call rstmap ;Allocate it inc a ;Next segment # and 0fh ;Check if all done jr nz,reslp2 ;Continue until done LD A,10h ;write new task and segment LD B,0 ;TASK 1 gets first 64K of memory reslp1: call rstmap ;Give TASK 1 a full 64k of space inc B inc A cp 20h jr nz,reslp1 fmap: ld b,a ;fill all the tasks' maps call rstmap inc a cp 0h jr nz,fmap ret Šsetup: xor a ld (mapram + 2),a ;a window for DMA device commands ld (map + 2),a ;image map updated ld (ersav),a ;null the error save byte ld a,hstrap ;initialize the mask register ld (mask),a ; -to trap on halts and stops ld (cmask),a ; Following code checks for presence of any ram in system ld hl,0ffffh ;top of ram ramchk: ld a,0f0h and h jr z,badram ;dont go below task0,seg1 ld (hl),a ;check it with a 00h cp (hl) jr z,nexchk dec hl ;try the next location jr ramchk nexchk: cpl ld (hl),a ;check it with an ff (might be ROM) cp (hl) ld (ersav + 1),hl ;store it away for printing jr z,tstsw dec hl ;try next location jr ramchk badram: ld hl,0badh ld (ersav + 1),hl ld a,'M' ld (ersav),a jp allerr ;if no ram force entry to monitor tstsw: ld a,(switch) ;get contents of switch and 0f8h ;Ignore irrelevent bits ld d,a ;d & e contain jump address ld e,0H cp 0 ;boot hard disk if switches are all on jp z,boothd cp 08h ;If switch 5 is off others are on jp z,nuboot ; - boot DMA controller cp 10h ;If switches 4 is off, others on jr z,djdma ; - boot the DJ-DMA floppy device check: ld a,(switch) ;test monitor switch bit 2,a ld a,1 ;normal task number ld (u.pc),de ;initialize the pc save area ld (ctask),a jr z,montor ;jump if monitor desired ld (mapram + 2),a ld (map + 2),a ;restore the maps jr nutask montor: xor a ;monitor task number ld de,cold ;monitor location nutask: ld hl,gobuff ;Write a routine to switch to new task ld (hl),03eh ;- because when the task register is Š inc hl ;- written into, the lower half of the ld (hl),a ;- prom goes away. inc hl ld (hl),032h inc hl ld (hl),02h inc hl ld (hl),04h inc hl ld (hl),nop ;6 nops for countdown sequence inc hl ld (hl),nop inc hl ld (hl),nop inc hl ld (hl),nop inc hl ld (hl),nop inc hl ld (hl),nop inc hl ld (hl),0c3h ;the jump op code inc hl ld (hl),e inc hl ld (hl),d ;**************************************************************** ;* * ;* Wunderbuss I/O and Mult I/O PIC initialization rou- * ;* tine. Interrupt vectors = restart locations. * ;* * ;**************************************************************** picset: xor a out (grpctl),a ld a,ivalu out (icw1),a ;initialize the first word ld a,hivect out (icw2),a ;initialize the second word ld a,normal out (icw4),a ;initialize the forth word ld a,picmask out (ocw1),a ;mask all interrupts ld a,eoi ;send PIC an End of Interrupt word out (ocw2),a ;clear the master interrupt requests out (ocw2),a ;clear the slaves interrupt requests ret ;**************************************************************** ;* * ;* DJ-DMA floppy disk boot routine (5.25 or 8 inch). * ;* * Š;**************************************************************** djdma: ld h,10h ; wait byte for 1 minute djlop0: ld bc,0000h djloop: ld a,(djstat) ;read the status back cp 040h ld de,(djstat - 2) ;d & e point to cold boot loader jr z,check ;if good status continue set gobuff cp 0ffh ; - else loop for good status jr z,nstat ;if 0ffh then force to a zero dec bc ld a,b or c jr nz,djloop dec h jr nz,djlop0 ;continue looping till a minute elapses ; DJ-DMA not responding correctly ld c,'F' ld a,(djstat) ld b,a ;save the error status ld a,(djstat - 2) ld d,a jr derror ;go to error--controller not ; - responding nstat: xor a ld (djstat),a ;null status byte ... signal DJ-DMA jr djloop ;**************************************************************** ;* * ;* Hard Disk Boot program for the DMA Winchester Controller. * ;* * ;**************************************************************** nuboot: ld bc,endboot - bootbl ;byte count ld hl,bootbl ;source ld de,chan ;destination ldir ;move the command ld hl,iopb ;point to default channel addr ld (hl),80h ;fill in the command channel address xor a inc hl ; -located at 50h to point to channel ld (hl),a ; -at 80h. inc hl ld (hl),a out (dmarst),a ;send the controller a reset ld de,010h hdrl: dec d ;wait for controller to process reset jr nz,hdrl call cloop Šhome: ld hl,-1 ;seek to home ld (chan + 1),hl ;- with ffff step pulses ld a,noop ld (statis - 1),a ;null the command byte ld a,1 ld (statis),a ;initialize the status byte call cloop rdata: ld de,chan ;destination ld bc,endrd - rdtbl ;byte count ld hl,rdtbl ;source ldir ;move the read sector command call cloop ld de,0100h ;point to beginning of DMA boot prog. jp check cloop: ld c,020h cloop0: out (attn),a ld de,0000h cloop1: ld a,(statis) ;check drive status cp 0ffh ;an FF means command completed ret z dec de ;wait for controller to respond ld a,e or d jr nz,cloop1 ;give it a couple seconds to respond ; Fall through to here on any error ld a,(statis) cp 01h jr nz,cloop2 dec c ;give it 10 tries if not rdy error jr nz,cloop0 ; - about 20 seconds cloop2: pop de ;re-align the stack pointer ld c,'H' ;save the device ld b,a ;save the status ld a,(cmmd) ;save the command ld d,a ;**************************************************************** ;* * ;* Enter here if DISK controllers don't respond correctly. * ;* Routine alters gobuff to point to the monitor cout routine. * ;* * ;**************************************************************** Š derror: ld a,c ld hl,ersav ld (hl),a ;store c for later inc hl ld (hl),b ;error status inc hl ld (hl),d ;command causing error allerr: xor a ld (ctask),a ld de,cold ;pointer to error print ld (u.pc),de ;save the pointer in t1 pc jp nutask ;**************************************************************** ;* * ;* Hard Disk Boot program for Decision 1 EPROM. * ;* For M26, M10, and M20. * ;* 11/4/81 BJG * ;**************************************************************** hdclop: ld de,0000h hdlop1: in a,(status) and b ret nz dec de ld a,d or e jr nz,hdlop1 jr hdcerr wait: ld h,010h wait0: ld de,0 wait1: in a,(status) and b ret z dec de ld a,d or e jr nz,wait1 dec h jr nz,wait0 pop hl ;re-align the stack pointer hdcerr: ld c,'D' ; D for HDCA error flag in a,(status) ;get the primary status ld b,a in a,(secstat) ;get the secondary status ld d,a jr derror boothd: ld a,drivea ;select out (functn),a ; drive A Š ld a,drenbl ;turn on drive out (contrl),a ; command register rloop: ld b,ready call wait ld a,dskrun ;enable the out (contrl),a ; controller waitz: in a,(status) ;test for heads at track 0 rra jr nc,sdone ld a,stepo ;execute out (functn),a ; the ld a,drivea ; step out out (functn),a ; command waitc: ld b,complt call hdclop jr waitz sdone: in a,(status) ;get an image ld c,a ; of the status reg iwait1: in a,(status) ;wait for sub c ; the index pulse jr z,iwait1 ; to arrive iwait2: in a,(status) ;wait for the sub c ; next index pulse jr nz,iwait2 ;test for head settle iwait3: in a,(status) sub c jr z,iwait3 ld a,header ;reset the out (commd),a ; buffer pointer xor a ; to header area out (data),a ;head 0 out (data),a ;track 0 inc a ;sector 1 out (data),a ld a,system ;system key out (data),a ld a,dread ;issue a out (commd),a ; read command waitd: ld b,opdone call hdclop in a,(data) ;low order byte of ld l,a ; bootstrap address ld e,a in a,(data) ;high order byte of ld h,a ; bootstrap address ld d,a and 0f0h ;check for 1st segment of task0 Š jr z,dxloop xor a ld (mapram + 2),a ;T0 map is as normal with no window lloop: in a,(data) ;load ld (de),a ; the inc e ; bootstrap jr nz,lloop ld d,h ;save the boot addr for later ld e,l ld a,01 jp check dxloop: ld a,d and 0fh ;strip the segment # or 010h ; force the load into seg 0 task 1 ld d,a jr lloop ;**************************************************************** ;* * ;* Rstmap writes the tasks memory allocation vectors. Upon * ;* entry the registers must contain: * ;* a = task number / task segment number to update * ;* high nibble = task # low nibble = segment # * ;* b = New allocation vector * ;* c = New allocation access * ;* * ;* Routine calculates the expression 600+(Accumulator) x 2 * ;* where accumulator contents are as listed above. All arit- * ;* hmetic and numbers are in Hex * ;* * ;**************************************************************** rstmap: ld l,a ;Get task and segment numbers ld h,0h add hl,hl ;multiply times 2 ex de,hl ;save calculated offset in D,E ld hl,mapram ;point to beginning of ram map call rstmxx ld hl,map ;point to image map at 200 rstmxx: add hl,de ;add offset to selected map ld (hl),b ;write the allocation vector to ram inc hl ;point to access ram ld (hl),c ;write access attributes to ram ret ;******************************************************** ;* * ;* The following code intitializes the I/O for * ;* the Decision 1 Motherboard and the Mult I/O. * ;* * ;******************************************************** Š uartst: ld d,3 ;start with uart 3 uarts0: ld a,d out (grpctl),a xor a out (lsr),a ;clear line status register out (ier),a ;initialialize interupt mask (off) dec d jr nz,uarts0 out (grpctl),a ;select sense switch port in a,(base+1) rlca rlca rlca and 07h ;mask insignificant bits cp 07h ;all off? ld d,0 jr z,default ;default if all off ld hl,btable ;point to baud rate table add a,a ld e,a add hl,de ;offset to selected baud rate ld c,(hl) inc hl ld b,(hl) ;bc = baud rate divisor value (D) jr setit default: ld bc,12 ;default baud rate is 9600 setit: inc d ld a,d out (grpctl),a ld a,dlab+wls1+wls0+stb out (lcr),a ;divisor access bit is on ld a,b out (dlm),a ;load high divisor register ld a,c out (dll),a ;load low divisor register ld a,wls1+wls0+stb out (lcr),a ;divisor access bit is off ld a,loop ;clear the shift register out (mcr),a ; - by looping back. in a,(rbr) ;clear receiver buffer xor a out (thr),a ;clear transmitter buffer call begin0 in a,(rbr) xor a out (thr),a call begin0 ;two times to make sure rduart: in a,(lsr) and dr ;check for data available jr z,rduart Š in a,(rbr) ;intitialize receiver buffer cp 0 jr z,contin ;jump if UARTS good urterr: push af ld a,'U' ld (ersav),a ;Uart error ld a,d ld (ersav + 2),a ;Uart # saved pop af ld (ersav + 1),a ;bad character saved xor a contin: out (mcr),a ld a,d cp 3 ;initialize all three uarts ret z jr setit begin0: in a,(lsr) and thre jr z,begin0 ret ; Baud rate selection table for Mult I/o or WB I/O btable: dw 1047 ;110 baud 0 0 0 dw 384 ;300 baud 0 0 1 dw 96 ;1200 baud 0 1 0 dw 48 ;2400 baud 0 1 1 dw 24 ;4800 baud 1 0 0 dw 12 ;9600 baud 1 0 1 dw 6 ;19200 baud 1 1 0 ; Load constants command for the DMA Winchester controller bootbl: db 10h ;direction --> track 0 db 0 ;low steps db 0 ;high steps db 03ch ;select drive 0 db 0 ;low dma address db 01 ;high dma address db 0 ;extended dma address db 0 ;argument 0 db stpdly ;argument 1 db hdsetl ;argument 2 db secsiz ;argument 3 db const ;load constants opcode db 0 ;clear status byte db 80h ;low link address db 0 ;high link address db 0 ;extended link address endboot equ $ Š ; Read sector 1, head 0, cyl 0 command for the HD-DMA: rdtbl: db 0 ;no seek db 0 db 0 db 07ch ;select drive 0, head 0 db 0 ;dma address of 100h db 1 db 0 db 0 ;low byte cylinder db 0 ;high byte cylinder db 0 ;head 0 db 0 ;sector 1 db 0 ;read command db 0 ;clear status endrd equ $ ; Dispatch table for the on-board diagnostic routines jtable equ $ jp regrd ;test all the readable registers db 0 jp regwr ;check all the writable registers but ; -task register db 0 jp tmap ;check map rams db 0 jp tram ;check read/write ram db 0 jp tfpp ;check fpp db 0 jp tbus ;check bus read/write addresses db 0 jp ntbus ;R/W bus with 055h and 0aah db 0 jr start ;yet to be defined ecode0 equ $ ;End of reset prom code ds 3f0h-(ecode0-rom0) ;Fill out the prom ;**************************************************************** ;* * ;* The following special piece of code is where the user task * ;* begins executing when a reset trap occurs. * ;* * ;**************************************************************** ld hl,djstat ld a,0h ld (mapram + 2),a ;t0 map points to t1 map seg 0 Š inc a start: ld sp,map jp getsw ;power-on or reset jump nop ;Fill out the prom. erom0 equ $ ds 400h-(erom0-rom0) .phase 800h ;**************************************************************** ;* * ;* This code is usuable by the supervisor task (task0) * ;* but is not accessible to any other tasks. Any trap * Š;* other than a reset will enable this half of the eprom * ;* as well. * ;* * ;**************************************************************** rom1 equ $ ;**************************************************************** ;* * ;* ===>> J U M P T A B L E <<=== * ;* * ;**************************************************************** svtrap: jp trappd ;trap routine, check out reason why tskbse: jp what ;vestigial nmap: jp putmap ;set up new allocation vector, access gotsk: jp gotask ;switch to new task getmap: jp gtmap ;get the old allocation vector, access dupmap: jp what ;vestigial what: jp monitor ;debugger/monitor called 'MON' restr: jp restor ;restore task 0 map to normal condition oldtask: jp gotsk ;jumps to last task before trap wrtask: jp writsk ;writes value in CTASK to task register wratsk: jp atask ;writes value in 'A' to task register trappd: ld de,-15 ;back up the users pc pop hl add hl,de ld (u.pc),hl ld a,(ctask) cp 0 jp z,suptrap pop de pop hl pop Af ld sp,(cstack) ;set up reg_save stack in supervisor alltrp: ex Af,Af' ;save user's auxiliary registers exx push hl push de push bc push Af push iy push ix ld a,i ;get interupt register push af ;save it ex Af',Af exx push hl ;- and save all user registers push de push bc push Af ld hl,(ctask) ;save the task and mask ld de,(u.sp) ;get the user's stack pointer ld bc,(u.pc) push de ;save the user's stack pointer push bc ;save the user's program counter push hl ;save the current task and mask ld (regsav),sp ;beginning address of reg save area ; - saved here. ;Stop switch calls the monitor - return will restore to "CTASK" ld a,l ;get the trapped task # cp 0 jr z,gowhat ;if trap was in task 0, go to monitor ld a,(stats) bit 4,a jr nz,gosupr ;go to super unless it was a stop trap gowhat: xor a ld (ctask),a call what jr gotask suptrap: pop de pop hl pop Af ld sp,(u.sp) jp alltrp ;Call the supervisor - a return will restore the task in "CTASK" Šgosupr: xor a ld (ctask),a call super jr gotask ;******************************************************** ;* * ;* Writsk will take the value in CTASK and write it * ;* to the TASK register. It then waits 6 instructions * ;* for the hardware delay and returns with traps set * ;* and operation in the task selected. The 'A' re- * ;* gister is not preserved, all others untouched. * ;* * ;******************************************************** writsk: ld a,(ctask) atask: ld (task),a ;update the task register and count nop ; - 7 instructions to delay for the nop ; - hardware swap counter. nop nop nop nop nop ret ;******************************************************** ;* * ;* Restore will restore Task 0's map with its old * ;* values. This assumes that if the map for task 0 * ;* has been changed, that only the actual map had * ;* been changed and that the image map was left in * ;* the condition before the change occurred. * ;* * ;******************************************************** restor: ld hl,map ;point to beginning of map image ld de,mapram ;point to beginning of actual map ld bc,01Fh ;all of task 0 map ldir ;**************************************************************** ;* * ;* Gotask restores all the task's registers and then * ;* switches to that task. * ;* * ;**************************************************************** gotask: ld hl,0 ;init hl for normal entry add hl,sp ntask: ld sp,hl pop hl ld (ctask),hl ;get back CTASK and CMASK pop hl ld (u.pc),hl ;get back the user's pc Š pop hl ld (u.sp),hl ;get back the user's sp pop Af ;get back the primary registers pop bc pop de pop hl ex Af',Af exx pop Af ;get back the interrupt register ld i,a ;restore it pop ix ;restore auxilliary registers pop iy ld hl,(u.pc) bcomnd: ld (user + 1),hl ;form jump to user's pc value @ user ld a,jmpop ld (user),a pop Af ;restore the alternate registers pop bc pop de ld hl,(ctask) ld (task),hl ;write the new task and mask pop hl ex Af,Af' exx ld sp,(u.sp) jp user ;******************************************************** ;* * ;* The following code will return with: * ;* Register A = task #/ segment # * ;* Register B = old allocation vector * ;* Register C = old access priviledges * ;* Upon entry, it expects the A register to have * ;* the desired task# / segment #. Consider this to be * ;* opposite of the putmap routine. * ;* * ;******************************************************** gtmap: ld l,a ;get task and segment numbers ld h,0h add hl,hl ;multiply times 2 ex de,hl ;save calculated offset in de ld hl,map ;point to beginning of map ram image add hl,de ;add offset to get desired map ld b,(HL) ;get old allocation vector inc hl ;offset to access map ld c,(HL) ;get old access priviledges ret ;******************************************************** ;* * ;* Putmap updates a task's allocation vectors and * ;* access atributes. Upon entry, registers must * ;* contain: * ;* a = task # / task segment # to update * ;* high nibble = task#, low nibble = segment# * ;* b = new allocation vector * ;* c = new access privilidges * ;* * ;* Routine calculates the expression 600 + (a) X 2 * ;* where a is as listed above. All arithmetic and * ;* numbers are in Hex. * ;* * ;******************************************************** putmap: ld l,a ;get task and segment number ld h,0h ; add hl,hl ;multiply times 2 ex de,hl ;save calculated offset in de Š ld hl,mapram ;point to beginning of ram map call putmxx ld hl,map ;point to beginning of image map putmxx: add hl,de ;add offset to selected map ld (hl),b ;write the allocation vector inc hl ;point to access attribute ram ld (hl),c ;write new access atributes ret ;******************************************************** ;* * ;* The following routines make up the debugging tool * ;* monitor * ;* * ;******************************************************** monitor: ld (monstk -2),sp ;save stack for 'u' & 'c' commands ld iy,(monstk-2) ld sp,monstk ld hl,(regsav) ;get the stack location ld de,27 ;number of saved registers push hl add hl,de ex de,hl pop hl ld bc,ustart push bc jp udi0 ;print out the registers cold: ld a,(ersav) ;retrieve the error byte if any ld c,a call ucout1 ;print it ld hl,(ersav + 1) ;retrieve disk command call uladr ustart: ld sp,monstk LD DE,USTART PUSH DE CALL UCRLF LD C,':' CALL ucout1 USTAR0: CALL UTI OR A JR Z,USTAR0 CP 'z'+1 JP NC,UERROR LD C,002H CP 'D' JR Z,udisp cp 'd' jr nz,ufill ; ; DISPLAY MEMORY XXXX TO XXXX ; ; UDISP: CALL UEXLF UDI0: CALL UCRLF CALL ULADR LD B,010H UDI1: CALL UBLK LD A,(HL) CALL ULBYTE CALL UHILOX DJNZ UDI1 JR UDI0 ; ; ; ; FILL MEMORY XXXX TO XXXX WITH XX ; ; Š; UFILL: CP 'F' JR z,ufill0 cp 'f' jr nz,ugoto ufill0: CALL UEXPR3 UFI0: LD (HL),C CALL UHILO JR NC,UFI0 POP DE JP USTART ; ; ; GOTO (EXECUTE) XXXX ; ; UGOTO: CP 'G' JR Z,ugoto0 cp 'g' jr nz,umtest ugoto0: CALL UEXPR1 CALL UCRLF POP HL JP (HL) ; ; ; TEST MEMORY XXXX TO XXXX ; ; UMTEST: CP 'T' JR Z,ut10 cp 't' jr nz,umove ut10: CALL UEXLF UT1: LD A,(HL) LD B,A CPL LD (HL),A XOR (HL) JR Z,UT2 PUSH DE LD E,A CALL UHLSP CALL UQI1 CALL UCRLF POP DE UT2: LD (HL),B CALL UHILOX JR UT1 ; ; ; MOVE DATA FROM XXXX TO XXXX ; ; UMOVE: CP 'M' Š JR Z,umvo0 cp 'm' jr nz,usubs umvo0: CALL UEXPR3 UMV0: LD A,(HL) LD (BC),A INC BC CALL UHILOX JR UMV0 USTORE: LD (IX+00H),A INC IX DEC E RET ; ; ; EXAMINE AND/OR REPLACE MEMORY DATA ; ; USUBS: CP 'S' JP Z,usuo0 cp 's' jp nz,uhexn usuo0: CALL UEXPR1 CALL UQCHK JP C,UERROR POP HL USU0: LD A,(HL) CALL ULBYTE LD C,02DH CALL UCOPCK RET C JR Z,USU1 PUSH HL LD HL,0 LD C,001H CALL UEX1 POP DE POP HL LD (HL),E LD A,B CP 00DH RET Z USU1: INC HL CALL UCRLF PUSH HL CALL ULADR CALL UBLK POP HL JR USU0 ; ; UEXLF: CALL UEXPR POP DE POP HL ; CR/LF OUTPUT Š; ; UCRLF: PUSH HL PUSH BC LD C,0DH CALL ucout1 LD C,0AH CALL ucout1 POP BC POP HL CALL UCSTS OR A RET Z ; ; CHECK FOR CONTROL CHARACTER ; ; UCCHK: CALL ucon1 AND 07FH CP 013H ;CONTROL-S JR Z,UCCHK CP 003H ;CONTROL-C RET NZ UERROR: CALL UMEMSIZ LD DE,UERROR PUSH DE LD C,'?' CALL ucout1 JP USTART UHLSP: CALL ULADR ; ; PRINT SPACE CHARACTER ; UBLK: LD C,020H ;******************************************************** ;* * ;* Console I/O routines for the Wunderbus I/O. These * ;* routines assume that the uart divisor latch has * ;* previously set (either on power up or in routine * ;* executed before a trap to this routine occurred. * ;* The character to output should be in the 'C' reg- * ;* ister, the character received is returned in the * ;* 'A' register. UCSTS returns with zero flag set * ;* when no character is waiting in the UART buffer, * ;* or with A = FFh if a character is waiting. * ;* * ;******************************************************** ucout1: call uconinit ucout2: in a,(lsr) ;get uart status and thre jr z,ucout2 ;loop until tbe Š ld a,c out (thr),a ;output the data to uart ret ucon1: call uconinit ucon2: in a,(lsr) ;get uart status and dr jr z,ucon2 ;wait until receive data available in a,(rbr) ;read the uart data register and 07fh ;strip parity ret ucsts: call uconinit in a,(lsr) ;read uart status and dr ret z ;return zero set if no character ld a,0ffh ret ;return a = ffh if character waiting uconinit: ld a,group1 out (grpctl),a ;set up for UART 1 ld a,wls0+wls1+stb out (lcr),a ;8 bit word, 2 bit stop bits ret ; CONVERT HEX TO ASCII UCONV: AND 00fh ADD A,090H DAA ADC A,040H DAA LD C,A RET ; ; GET PARAMETERS 1,2,OR 3 ; UEXPR3: INC C CALL UEXPR CALL UCRLF POP BC POP DE POP HL RET UEXPR1: LD C,001H UEXPR: LD HL,0 UEX0: CALL UTI UEX1: LD B,A CALL UNIBBLE JR C,UEX2 ADD HL,HL ADD HL,HL Š ADD HL,HL ADD HL,HL OR L LD L,A JR UEX0 UEX2: EX (SP),HL PUSH HL LD A,B CALL UQCHK JR NC,UEX3 DEC C RET Z UEX3: JP NZ,UERROR DEC C JR NZ,UEXPR RET UHILOX: CALL UHILO RET NC POP DE RET UHILO: INC HL LD A,H OR L SCF RET Z LD A,E SUB L LD A,D SBC A,H RET ; ; HEXADECIMAL ARITHMETIC ; UHEXN: CP 'H' JR Z,uhexd cp 'h' jr nz,uport uhexd: CALL UEXLF PUSH HL ADD HL,DE CALL UHLSP POP HL OR A SBC HL,DE ; ; CONVERT HL REGISTER TO ASCII ; ULADR: LD A,H CALL ULBYTE LD A,L ; ; CONVERT A REGISTER TO ASCII ; ULBYTE: PUSH AF RRCA Š RRCA RRCA RRCA CALL UDBLC POP AF UDBLC: CALL UCONV JP ucout1 ;checked UMEMSIZ: RET UNIBBLE: cp 'a' ;is it less than lower case 'a'? jr c,unibok ;take jump if so cp 'z'+1 ;less than a lower case 'z'? ccf ;set carry and return if > 'z' ret c sub ' ' ;convert to upper case unibok: SUB 030H RET C cp 017h ccf RET C CP 00AH CCF RET NC SUB 007H CP 00AH RET UCOPCK: CALL ucout1 UPCHK: CALL UTI ; ; CHARACTER CHECK ; UQCHK: CP 020H RET Z CP 02CH RET Z CP 00DH SCF RET Z CCF RET ; ; ECHO CONSOLE ; UTI: CALL ucon1 INC A RET Z DEC A AND 07FH RET Z CP 000H RET Z Š CP 04EH RET Z CP 06EH RET Z PUSH BC LD C,A CALL ucout1 LD A,C POP BC RET ; ; READ/WRITE TO I/O PORT ; UPORT: CP 'O' JR Z,UQOUT CP 'o' jr z,uqout CP 'I' JR Z,uin cp 'i' jr z,uin JR UVERIFY UIN: CALL UEXPR1 LD C,0AH CALL ucout1 POP BC UQ0: IN E,(C) UQI1: LD B,008H CALL UBLK UQI2: SLA E LD A,018H ADC A,A LD C,A CALL ucout1 DJNZ UQI2 RET UQOUT: CALL UEXPR POP DE POP BC OUT (C),E RET ; ; ; ; ; VERIFY MEMORY XXXX TO XXXX WITH XXXX ; UVERIFY: CP 'V' JR Z,uver0 cp 'v' jr nz,uretrn uver0: call uexpr3 UVERIO: LD A,(BC) Š CP (HL) JR Z,U..B PUSH BC CALL UCERR POP BC U..B: INC BC CALL UHILOX JR UVERIO ; Return to task which just trapped with old pc and registers restored ; All registers are saved!! uretrn: cp 'C' jr z,uretr1 cp 'c' jr nz,ucontr uretr1: ld sp,iy ;get back the user save stack pop de ; ... the return address pop hl ; ... Ctask/Cmask ld a,h or 08h ;set the run bit for 'run' ld h,a push hl ;restore the stack push de ret ;return to user through 'gotask' ; Return to trapped task, execute next instruction and trap back ; All registers are saved but the mask is changed!! ucontr: cp 'U' jr z,ucont1 cp 'u' jr nz,uboot ucont1: ld sp,iy ;get back the user save stack pop de ;... the return address pop hl ;... CTASK/CMASK ld a,h and 0f6h ;force mask for stop and run enble low ld h,a push hl ;restore the stack push de ret ;return to user through 'gotask' ; Jump to the cpu switch address into task specified by CTASK ; No registers are preserved!! uboot: cp 'B' jr z,uboot1 cp 'b' jp nz,uerror uboot1: ex Af',Af exx xor a inc a ld (mapram + 2),a ;restore the actual map ld (map + 2),a ;restore map image ld a,(switch) and 0f8h cp 0 ;HDCA Boot? jr z,uboot2 cp 8 ;HD-DMA Boot? jr z,uboot2 cp 10h ;DJ-DMA Boot? jr z,uboot2 ld h,a ;Memory Address jump ld l,0 jp bcomnd uboot2: ld hl,(u.pc) ;get the boot address for controllers jp bcomnd ; MEMORY MISMATCH PRINTOUT ; UCERR: LD B,A CALL UHLSP Š LD A,(HL) CALL ULBYTE CALL UBLK LD A,B CALL ULBYTE JP UCRLF ecode1 equ $ ds 3edh - (ecode1-rom1) serial: dw 0ffffh ;Micronix serialization word db 0ffh ;******************************************************** ;* * ;* The following piece of code is where the user * ;* task begins execution whenever a trap occurs. * ;* The users registers and sp are saved in the * ;* temporary users store area. * ;* * ;******************************************************** nop ;must be nop to void a halt ld (u.sp),sp ;save the users stack pointer ld sp,begsave ;set sp to the temporary save area push af push hl push de nop call trappd ;go to supervisor trap via temp halt ;halt here allows T0 to halt erom1 equ $ ds 400h-(erom1-rom1) fpp0: ds 8 fpp1: ds 1 end