;======================================================= ; Pilot: Serial Interface ; ----------------------------------------------------- ; W65C02 CPU at 1.8432MHz ; AT28C256 ROM $8000-$FDFF & $FF00-$FFFF ; MS62256 RAM $0000-$7FFF ; W65C51 ACIA $FE14-$FE17 ; ICL232 RS232 Driver ; 74LS30 $FEXX Range IO Select ; 74LS00 Not Gates, ROM Select, Write Sync ; 74LS138 ACIA Select ; ----------------------------------------------------- ; USE: ; Assemble with DASM 6502 ; Write this BIN to $FC00 ; Note the first two bytes are the origin ; when assembled with dasm these must ; be removed before writing the bin ; Write rts at $C000 Main Location ; Write rts at $C004 Interrupt Location ; Connect to Serial Port ; In a terminal program type: PILOT H ; ----------------------------------------------------- ; TODO: ; memcmp for checking pilot addressing ; add pilot addressing ; move hello to user area ; make perminent version ; write programming tutorials ; standardize function locations and calling for compatability with future versions ; ----------------------------------------------------- ; Copyright 2017 Marcus Kelly (Desk Machines) ;======================================================= processor 6502 ACIA_DELAY = $09 ACIA_DATA = $FE14 ACIA_STATUS = $FE15 ACIA_COMMAND = $FE16 ACIA_CONTROL = $FE17 WRITE_ROUTINE = $7E00 COPY_ROUTINE = WRITE_ROUTINE+memwritee-memwrite DELAY_COUNT = $7FFA DATA_BYTE = $7FFC BUF_INDX = $7FFE BUFFER = $7F00 USER_MAIN = $C000 USER_INT = $C004 SADDRESS_LOW = $FA SADDRESS_HIGH = $FB ADDRESS_LOW = $FC ADDRESS_HIGH = $FD PTR_LOW = $FE PTR_HIGH = $FF org $FC00 ;------------------------------------------------------- ; To Uppercase ;------------------------------------------------------- toup: cmp #$61 ; Make sure we are lower case bcc toup1 cmp #$7A bcs toup1 and #$DF ; And out lowercase bit toup1: rts ; Return ;------------------------------------------------------- ; Hex Nibble In ;------------------------------------------------------- hnin: jsr toup ; Make sure byte is upper case hnin1: clc ; Subtract "0" sbc #$2F cmp #$0A ; Check if we are greater than 9 bcc hnin2 clc ; if greater than 9 subtract 6 sbc #$06 hnin2: rts ; Return ;------------------------------------------------------- ; Hex Nibble Out ;------------------------------------------------------- hnout: pha ; Save a and #$0F ; Clear upper bitss clc ; Add "0" adc #$30 cmp #$3A ; Check greater than "9" bcc hnout2 clc ; If greater than "9" add 7 adc #$07 hnout2: jsr cout ; Output Character pla ; Restore a rts ; Return ;------------------------------------------------------- ; Hex Out ;------------------------------------------------------- hout: pha ; Save a ror ; Rotate in upper Nibble ror ror ror jsr hnout ; Output upper Nibble pla ; Restore A jsr hnout ; Output lower Nibble rts ; Return ;------------------------------------------------------- ; String Out ;------------------------------------------------------- stout: ldy #$00 ; Zero counter stout2: lda (PTR_LOW),y ; Load byte text+x beq stout3 ; If zero wait for key jsr cout ; Output character iny ; Increment pointer jmp stout2 ; Write next character stout3: rts ; Return ;------------------------------------------------------- ; Character Out ;------------------------------------------------------- cout: pha ; Save A cout2: ;lda ACIA_STATUS ; Read transmit buffer full bit ;and #$10 ;beq cout2 ; Loop if transmit buffer full lda #ACIA_DELAY ; W65C51 Error use delay jsr delay jsr delay jsr delay pla ; Restore A sta ACIA_DATA ; Output byte to serial rts ; Return ;------------------------------------------------------- ; Command Help ;------------------------------------------------------- chelp: lda #help ; Load high help sta PTR_HIGH jsr stout ; Print String rts ; Return help: dc "help: h", $0D, $0A dc "read: r mmmm", $0D, $0A dc "dump: d mmmm", $0D, $0A dc "move: m ssss dddd cc", $0D, $0A dc "write: w mmmm bb", $0D, $0A dc "call: c mmmm", $0D, $0A dc "jump: j mmmm", $0D, $0A, $00 ;dc "uasm: u mmmm", $0D, $0A, $00 ;dc "asm: a [mmmm] opcode", $0D, $0A, $00 ;dc "trace: t [mmmm]", $0D, $0A, $00 ;dc "pass: p [mmmm]", $0D, $0A, $00 ;dc "load: l mmmm file", $0D, $0A, $00 ;dc "save: s mmmm cccc file", $0D, $0A, $00 ;------------------------------------------------------- ; Ascii 2 Hex ;------------------------------------------------------- a2h: lda (PTR_LOW),y ; Get byte jsr hnin ; Convert to ascii clc ; Rotate into upper nibble rol rol rol rol and #$F0 ; Clear lower nibble sta DATA_BYTE ; Save iny ; Increment Pointer lda (PTR_LOW),y ; Get next byte jsr hnin ; Convert to ascii and #$0F ; Clear upper nibble ora DATA_BYTE ; or together result in a rts ; return ;------------------------------------------------------- ; Get Address ;------------------------------------------------------- gaddr: iny ; Increment pointer iny jsr a2h ; Convert to hex sta ADDRESS_HIGH ; Store high address iny ; Increment pointer jsr a2h ; Convert to hex sta ADDRESS_LOW ; Store low address rts ; Return ;------------------------------------------------------- ; Get Data ;------------------------------------------------------- gdata: iny ; Increment pointer iny jsr a2h ; Convert to hex sta DATA_BYTE ; Store data rts ; Return ;------------------------------------------------------- ; CRLF ;------------------------------------------------------- crlf: lda #$0D ; Print carrage return jsr cout lda #$0A ; Print line feed jsr cout rts ; Return ;------------------------------------------------------- ; Command Read ;------------------------------------------------------- cread: jsr gaddr ; Get address from ascii string lda ADDRESS_HIGH ; Print high address jsr hout lda ADDRESS_LOW ; Print low address jsr hout lda #$3A ; Print ":" jsr cout lda #$20 ; Print space jsr cout ldy #$0 ; Print byte at that address lda (ADDRESS_LOW),y jsr hout jsr crlf ; Print crlf rts ; Return ;------------------------------------------------------- ; Command Dump ;------------------------------------------------------- cdump: jsr gaddr ; Get address from ascii ldy #$0 ; Zero data pointer ldx #$08 ; Display 8 rows stx DATA_BYTE ; Store row counter cdump1: lda ADDRESS_HIGH ; Print high address jsr hout tya ; Add y byte counter to address for next row clc adc ADDRESS_LOW sta ADDRESS_LOW ; Store new address ldy #$0 ; Zero pointer as address now points 16 bytes further lda ADDRESS_LOW ; Print low address jsr hout lda #$3A ; Print ":" jsr cout ldx #$10 ; Display 16 bytes cdump2: lda #$20 ; Print space jsr cout lda (ADDRESS_LOW),y ; Print byte jsr hout iny ; Next byte dex bne cdump2 jsr crlf ; Next row dec DATA_BYTE bne cdump1 ;jsr crlf rts ; Return ;------------------------------------------------------- ; Memory Write Routine (Transfered to ram) ; ADDRESS loaded with address ; DATA_BYTE loaded with byte to write ;------------------------------------------------------- memwrite: ldy #$00 ; Zero pointer lda DATA_BYTE ; Get byte to store sta (ADDRESS_LOW),y ; Store Byte lda ADDRESS_HIGH ; Check if we are writing to IO cmp #$FE beq memwrite3 ; If IO skip EEPROM write done check memwrite2: lda (ADDRESS_LOW),y ; Check to make sure EEPROM returns correct data cmp DATA_BYTE ; before running code out of EEPROM bne memwrite2 memwrite3: rts ; Return memwritee: ;------------------------------------------------------- ; Memory Copy Routine (Transfered to ram) ; SADDRESS Source ; ADDRESS Destination ; x number of bytes to write ;------------------------------------------------------- memcopy: ldy #$00 ; Zero pointer memcopy2: lda (SADDRESS_LOW),y ; Get byte from source address sta DATA_BYTE sta (ADDRESS_LOW),y ; Store byte at destination address memcopy3: lda (SADDRESS_LOW),y ; Check to make sure EEPROM returnss correct data cmp DATA_BYTE ; before next write bne memcopy3 iny ; Increment pointer dex ; Decriment byte count bne memcopy2 ; next byte rts ; return memcopye: ;------------------------------------------------------- ; Memory Compare Routine ; SADDRESS Address 1 ; ADDRESS Address 2 ; x number of bytes to compare ;------------------------------------------------------- memcmp: rts ;------------------------------------------------------- ; Command Move ;------------------------------------------------------- cmove: jsr gaddr ; Get source address lda ADDRESS_LOW ; Load source address sta SADDRESS_LOW lda ADDRESS_HIGH sta SADDRESS_HIGH jsr gaddr ; Get destination address jsr gdata ldx DATA_BYTE ; Get count jsr COPY_ROUTINE ; Ram location of memcopy rts ; Return ;------------------------------------------------------ ; Command write ;------------------------------------------------------- cwrite: jsr gaddr ; Get address from string jsr gdata ; Get data from string jsr WRITE_ROUTINE ; Ram location for memwrite rts ; Return ;------------------------------------------------------ ; Command Call ;------------------------------------------------------- ccall: jsr gaddr ; Get address jsr [ADDRESS_LOW] ; Call address rts ; Return ;------------------------------------------------------- ; Command Jump ;------------------------------------------------------- cjump: jsr gaddr ; Get address jmp [ADDRESS_LOW] ; Jump to address rts ; Return ;------------------------------------------------------- ; IO Area can't be seen by the computer ;------------------------------------------------------- org $FE00 dc "(C)Copyright 2017 DeskMachines", $0D, $0A dc "Version 0.1", $0D, $0A dc "Revision 1", $0D, $0A dc "Build 1", $0D, $0A ;------------------------------------------------------- ; Setup ;------------------------------------------------------- org $FF00 main: cld ; Set math mode cli ; Turn on interrupts ;------------------------------------------------------- ; Initialize Stack ;------------------------------------------------------- init_stack: ldx #$FF ; Setup stack pointer txs ;------------------------------------------------------- ; Initialize Buffer ;------------------------------------------------------- init_buffer: lda #$00 ; Zero buffer index sta BUF_INDX ;------------------------------------------------------- ; Initialize Write Routines ;------------------------------------------------------- init_write: lda #memwrite sta SADDRESS_HIGH lda #WRITE_ROUTINE sta ADDRESS_HIGH ldx #memcopye-memwrite ; Copy both memwrite and memcoy jsr memcopy ; Copy routines to new ram location ;------------------------------------------------------- ; Initialize Serial ;------------------------------------------------------- init_acia: lda #ACIA_DELAY ; W65C51 Error use delay jsr delay jsr delay jsr delay lda #$09 ; No parity, no echo, no interrupt sta ACIA_COMMAND lda #$1E ; 1 stop bit, 8 data bits, 9600 baud sta ACIA_CONTROL ;------------------------------------------------------- ; Print "Hello World!" ;------------------------------------------------------- write: lda #text ; ... and the high byte sta PTR_HIGH jsr stout ; then call STOUT. jsr USER_MAIN ; Jump to user main routine die: jmp die ; Die routine ;------------------------------------------------------- ; Delay (Move to $FDXX) ;------------------------------------------------------- delay: sta DELAY_COUNT pha ; Save a txa ; Save x pha delay1: ldx #$FF ; Delay value delay2: dex ; Decrement delay value bne delay2 ; Keep going until we reach zero dec DELAY_COUNT ; (enabling this makes the computer very slow) bne delay1 pla ; Restore x tax pla ; Restore a rts ; Return ;------------------------------------------------------- ; Interrupt ;------------------------------------------------------- int: sei ; Turn off interrupts pha ; Save A tya ; Save Y pha lda ACIA_STATUS ; Get Status lda #BUFFER ; Load high buffer sta PTR_HIGH lda BUF_INDX ; load buffer ptr into y tay lda ACIA_DATA ; Get character jsr toup ; To upper case cmp #$0D ; Check for carrage return beq intCommand sta (PTR_LOW),y ; Store byte in buffer iny ; Increment buffer index tya sta BUF_INDX jmp intDone ; We are done intCommand: lda #$0D ; Store carrage return sta (PTR_LOW),y iny lda #$0A ; Store line feed sta (PTR_LOW),y iny lda #$00 ; Store zero sta (PTR_LOW),y jsr stout ; Print received command lda #$00 sta BUF_INDX ; Reset buffer index ; parser code ldy #$00 ; Zero pointer lda (PTR_LOW),y ; Load first byte cmp #"H" ; Check if Help command bne intNotH jsr chelp jmp intDone intNotH: cmp #"W" ; Check if Write command bne intNotW jsr cwrite jmp intDone intNotW: cmp #"D" ; Check if Dump command bne intNotD jsr cdump jmp intDone intNotD: cmp #"M" ; Check if Move command bne intNotM jsr cmove jmp intDone intNotM: cmp #"R" ; Check if Read command bne intNotR jsr cread jmp intDone intNotR: ; Check if Call command cmp #"C" bne intNotR jsr ccall jmp intDone intNotC: cmp #"J" ; Check if Jump command bne intDone jsr cjump intDone: pla ; Restore Y tay pla ; Restore A cli ; Turn on interrupts jsr USER_INT ; Jump to user interrupt routine nmi: rti ; Return from Interrupt ;------------------------------------------------------- ; Data ;------------------------------------------------------- text: dc "Hello!", $0D, $0A, $00 ;------------------------------------------------------- ; Vectors ;------------------------------------------------------- org $FFFA dc.w nmi ; NMI dc.w main ; Reset dc.w int ; IRQ/BRK