diff --git a/demos/iec/apple1.lm b/demos/iec/apple1.lm new file mode 100644 index 0000000..a0df60e --- /dev/null +++ b/demos/iec/apple1.lm @@ -0,0 +1,18 @@ +;======================================================================================= +; APPLE1 SPECIFIC DEFINES +;======================================================================================= + +// TODO ascii encoding ? + +const WOZMON = $FF1F ; enters monitor +const ECHO = $FFEF ; output ascii character in A (A not destroyed) +const PRBYTE = $FFDC ; print hex byte in A (A destroyed) +const KEY_DATA = $d010 ; read key +const KEY_CTRL = $d011 ; control port +const TERM_DATA = $d012 ; write ascii +const TERM_CTRL = $d013 ; control port +const INBUFFER = $0200 ; woz monitor input buffer +const INBUFSIZE = $80 ; woz monitor input buffer size +const CR = $0D ; carriage return + + diff --git a/demos/iec/apple1_code.lm b/demos/iec/apple1_code.lm new file mode 100644 index 0000000..b0574a1 --- /dev/null +++ b/demos/iec/apple1_code.lm @@ -0,0 +1,22 @@ +;======================================================================================= +; APPLE1 SPECIFIC CODE +;======================================================================================= + +sub woz_puts() + ldy #0 + do + lda (ptr),y + if zero then exit do + jsr ECHO + iny + loop while not zero +end sub + +sub getkey() + do + lda KEY_CTRL + loop while not negative + lda KEY_DATA + and #$7f +end sub + diff --git a/demos/iec/c64.lm b/demos/iec/c64.lm new file mode 100644 index 0000000..d2eb1c5 --- /dev/null +++ b/demos/iec/c64.lm @@ -0,0 +1,68 @@ + processor 6502 + +; Kernal entries + +const GETIN = $ffe4 ; getin rom kernel routine +const CLRSCN = $e544 ; clear screen +const PRNSTR = $ab1e ; print string in A/Y, 0 terminated +const GOHOME = $e566 ; go home +const PRNINT = $bdcd ; print integer in A/X + +; zero page + +const cursor_ptr = 209 +const jiffy_clock = 162 +const CRSRCOL = 646 + +; registers + +; color costants + +const color_black = 0 +const color_white = 1 +const color_red = 2 +const color_cyan = 3 +const color_magenta = 4 +const color_green = 5 +const color_blue = 6 +const color_yellow = 7 + +; screen costants + +const SCREEN_COLS = 40 +const SCREEN_ROWS = 25 +const VIDEO_MEMORY = 1024 +const COLOR_MEMORY = 55296 +const COLOR_PAGE_OFFSET = ((color_memory - VIDEO_MEMORY) / 256) +const BASIC_RAM = 2049 +const RASTER = $d012 +const ROMCHAR = 32768 + +; useful macros + + macro cls + jsr CLRSCN + end macro + + mac print + lda #[[{1}_pos]%256] + sta cursor_ptr + lda #[[{1}_pos]/256] + sta cursor_ptr+1 + lda #[{1}%256] + ldy #[{1}/256] + jsr my_print + endm + + macro waitkey + pha + txa : pha + tya : pha +.lab1 + jsr GETIN + cmp #0 + beq .lab1 + pla : tay + pla : tax + pla + end macro diff --git a/demos/iec/docs/commodore-iec-disected.pdf b/demos/iec/docs/commodore-iec-disected.pdf new file mode 100644 index 0000000..8675bb0 Binary files /dev/null and b/demos/iec/docs/commodore-iec-disected.pdf differ diff --git a/demos/iec/docs/disegno.jpg b/demos/iec/docs/disegno.jpg new file mode 100644 index 0000000..50736b9 Binary files /dev/null and b/demos/iec/docs/disegno.jpg differ diff --git a/demos/iec/docs/disegno1.jpg b/demos/iec/docs/disegno1.jpg new file mode 100644 index 0000000..68d1e9e Binary files /dev/null and b/demos/iec/docs/disegno1.jpg differ diff --git a/demos/iec/iec.lm b/demos/iec/iec.lm new file mode 100644 index 0000000..9ce30a2 --- /dev/null +++ b/demos/iec/iec.lm @@ -0,0 +1,110 @@ + processor 6502 + + #ifdef C64 then include "c64.lm" + #ifdef C64 then org 2049 + + #ifdef APPLE1 then include "apple1.lm" + #ifdef APPLE1 then org $280 + + include "macros.lm" + include "macros_16.lm" + +dim ptr as word at 254 ; useful zero page pointer + +#ifdef C64 +basic start + 10 sys {main} +basic end +#endif + +main: + PRINTMSG #MSG_OK + + call save_file + PRINTMSG #MSG_OK + + ; clears file content at absolute address + ld16 ptr, #file_content + lda #88 ;'X' + for y=#0 to #15 + sta (ptr),y + next + + ; clears file content at relative address + ld16 ptr, #relative_buffer + lda #88 ;'X' + for y=#0 to #15 + sta (ptr),y + next + + ; do not perform VERIFY when loading + ld VERCK, #0 + + ; prints file content loaded at relative address + PRINTMSG #MSG_RELATIVE_IS + PRINTMSG #relative_buffer + PRINTMSG #MSG_ABSOLUTE_IS + PRINTMSG #file_content + + call load_file_relative + PRINTMSG #MSG_OK + call load_file_absolute + PRINTMSG #MSG_OK + + ; prints file content loaded at relative address + PRINTMSG #MSG_RELATIVE_IS + PRINTMSG #relative_buffer + PRINTMSG #MSG_ABSOLUTE_IS + PRINTMSG #file_content + rts + +save_file: + JSR InitPia + ld16 FNADR, #file_name_test + call CalcFileNameLength + ld16 STAL, #file_content + ld16 EAL, #file_content_end + ld FA, #8 + ld SA, #1 + call SAVE + rts + +load_file_relative: + JSR InitPia + ld16 FNADR, #file_name_test + call CalcFileNameLength + ld16 MEMUSS, #relative_buffer + ld FA, #8 + ld SA, #0 + call LOAD + rts + +load_file_absolute: + JSR InitPia + ld16 FNADR, #file_name_test + call CalcFileNameLength + ld FA, #8 + ld SA, #1 + call LOAD + rts + +include "kernal.lm" + +#ifdef APPLE1 then include "apple1_code.lm" + +file_name_test: + byte "prova",0 + +file_content: + byte "0123456789ABCDEF" +file_content_end: + byte 13,0 ; filler that allows print as string + +relative_buffer: + byte "----------------" +relative_buffer_end: + byte 13,0 ; filler that allows print as string + +MSG_OK: byte "OK", 13, 13, 0 +MSG_RELATIVE_IS: byte "RELATIVE IS: ",0 +MSG_ABSOLUTE_IS: byte "ABSOLUTE IS: ",0 diff --git a/demos/iec/kernal.lm b/demos/iec/kernal.lm new file mode 100644 index 0000000..0cdc24d --- /dev/null +++ b/demos/iec/kernal.lm @@ -0,0 +1,174 @@ +; Adapted from https://commodore.international/kim-iec/kim1541_public.asm + +; zero page locations +STATUS = $90 ;I/O OPERATION STATUS BYTE +C3P0 = $94 ;IEEE BUFFERED CHAR FLAG +BSOUR = $95 ;CHAR BUFFER FOR IEEE +R2D2 = $A3 ;SERIAL BUS USAGE +BSOUR1 = $A4 ;TEMP USED BY SERIAL ROUTINE +COUNT = $A5 ;TEMP USED BY SERIAL ROUTINE +FNLEN = $B7 ;FILENAME LENGTH +FNADR = $BB ;FILENAME ADDRESS +FA = $BA ;FILE PRIMARY ADDRESS +SA = $B9 ;FILE SECONDARY ADDRESS +STAL = $AA ;SAVE END ADDR LOW BYTE FOR SAVE ROUTINE +STAH = $AB ;SAVE END ADDR HIGH BYTE FOR SAVE ROUTINE +SAL = $AC ;START ADDR LOW BYTE FOR SAVE ROUTINE +SAH = $AD ;START ADDR HIGH BYTE FOR SAVE ROUTINE +EAL = $AE ;END ADDRESS LOW BYTE +EAH = $AF ;END ADDRESS HIGH BYTE +MEMUSS = $C3 ;USER SPECIFIED FILE LOAD ADDRESS +VERCK = $0A ;LOAD OR VERIFY FLAG +SPERR = 16 ;VERIFY ERROR IN STATUS +FNAME = $27 ;FILENAME + +#ifdef C64 + const D2PRA = $DD00 ;CIA2 PERIPHERAL DATA REGISTER A ON C64 + const D2DDRA = $DD02 ;CIA2 PERIPHERAL DATA DIR REGISTER A ON C64 + const D1T2H = $DC07 ;CIA1 TIMER B HIGH BYTE VALUE + const D1ICR = $DC0D ;CIA1 INTERRUPT CONTROL REGISTER + const D1CRB = $DC0F ;CIA1 CONTROL REGISTER TIMER B + const TIMRB = $19 ;6526 CRB ENABLE ONE-SHOT TB + + const BIT_ATN_OUT = %00001000 ; ($08) CIA2 at $DD00 Bit 3: ATN OUT + const BIT_CLK_OUT = %00010000 ; ($10) CIA2 at $DD00 Bit 4: CLOCK OUT + const BIT_DATA_OUT = %00100000 ; ($20) CIA2 at $DD00 Bit 5: DATA OUT + const BIT_CLK_IN = %01000000 ; ($40) CIA2 at $DD00 Bit 6: CLOCK IN + const BIT_DATA_IN = %10000000 ; ($80) CIA2 at $DD00 Bit 7: DATA IN +#endif + +#ifdef APPLE1 + const D2PRA = $A000 ;VIA PORT B ON APPLE1 + const D2DDRA = $A002 ;VIA PORT B DATA DIRECTION REGISTER ON APPLE1 + const D1ACR = $A00B ;VIA ACR ON APPLE1 + const D2IFR = $A00D ;VIA IFR ON APPLE1 + const D2T2H = $A009 ;VIA TIMER 2 HIGH BYTE + + const TIMRB = #%01000000 ; FREE RUNNING T1 T2 ONESHOT D1 + + const BIT_ATN_OUT = %00000100 ; Bit 2: ATN OUT + const BIT_CLK_OUT = %00001000 ; Bit 3: CLOCK OUT + const BIT_DATA_OUT = %00010000 ; Bit 4: DATA OUT + const BIT_CLK_IN = %00100000 ; Bit 5: CLOCK IN + const BIT_DATA_IN = %01000000 ; Bit 6: DATA IN +#endif + +/* +byte *const VIA_PORTB = (byte *) 0xA000; // port B register +byte *const VIA_PORTA = (byte *) 0xA001; // port A register +byte *const VIA_DDRB = (byte *) 0xA002; // port A data direction register +byte *const VIA_DDRA = (byte *) 0xA003; // port B data direction register +byte *const VIA_T1CL = (byte *) 0xA004; // +byte *const VIA_T1CH = (byte *) 0xA005; // +byte *const VIA_T1LL = (byte *) 0xA006; // +byte *const VIA_T1LH = (byte *) 0xA007; // +byte *const VIA_T2CL = (byte *) 0xA008; // +byte *const VIA_T2CH = (byte *) 0xA009; // +byte *const VIA_SR = (byte *) 0xA00A; // +byte *const VIA_ACR = (byte *) 0xA00B; // +byte *const VIA_PCR = (byte *) 0xA00C; // +byte *const VIA_IFR = (byte *) 0xA00D; // +byte *const VIA_IER = (byte *) 0xA00E; // +byte *const VIA_PORTANH = (byte *) 0xA00F; // +*/ + +const PRA_INIT_VALUE = $FF-BIT_ATN_OUT-BIT_CLK_OUT-BIT_DATA_OUT-BIT_CLK_IN-BIT_DATA_IN ; all IEC bits to "0" +const PRA_INIT_DIR = $FF-BIT_CLK_IN-BIT_DATA_IN ; CLK_IN AND DATA_IN "0", others "1" + +; make "ASL A" compatible with "ASL" +MACRO ASL "A" + ASL +END MACRO + +include "kernal_serial.lm" +include "kernal_load.lm" +include "kernal_save.lm" + +MACRO PRINTMSG const + #ifdef APPLE1 + LD16 ptr, #{1} + call print_string + #endif + #ifdef C64 + LD16 ptr, #{1} + call print_string + #endif +END MACRO + +LUKING: + PRINTMSG #MSG_SEARCHING + RTS + +LODING: + PRINTMSG #MSG_LOADING + RTS + +SAVING: + PRINTMSG #MSG_SAVING + RTS + +ERROR8: + PRINTMSG #MSG_MISSING + RTS + +ERROR4: + PRINTMSG #MSG_NOT_FOUND + RTS + +ERROR5: + PRINTMSG #MSG_DEVICE_NP + RTS + +MSG_SEARCHING: BYTE "searching",13,0 +MSG_LOADING: BYTE "loading",13,0 +MSG_SAVING: BYTE "saving",13,0 +MSG_MISSING: BYTE "?missing file name",13,0 +MSG_NOT_FOUND: BYTE "?file not found",13,0 +MSG_DEVICE_NP: BYTE "?device not present",13,0 + +SUB print_string() + tya : pha + txa : pha + #ifdef APPLE1 + call woz_puts + #endif + #ifdef C64 + lda ptr + ldy ptr+1 + call PRNSTR + #endif + pla : tax + pla : tay +END SUB + +SUB CalcFileNameLength() + LDY #$FF + DO + INY + LDA (FNADR),Y + LOOP WHILE NOT ZERO + STY FNLEN +END SUB + +SUB InitPia() + CLD ; NO DECIMAL MODE + SEI ; NO INTERRUPTS + + #ifdef C64 + LD D2PRA, #PRA_INIT_VALUE ;SETS ALL IEC BITS TO LOW ($07) (#%00000111) + LD D2DDRA, #PRA_INIT_DIR ;SET DATA DIRECTION FOR REGISTER A ($3f) (#%00111111) + #endif + + #ifdef APPLE1 + LD D2PRA, #PRA_INIT_VALUE ;SETS ALL IEC BITS TO LOW + LD D2DDRA, #PRA_INIT_DIR ;SET DATA DIRECTION FOR REGISTER A + LD D1ACR, #TIMRB ;FREE RUNNING T1 T2 ONESHOT D1 (#%01000000) + lda #0 + sta STATUS + sta C3P0 + sta BSOUR + sta R2D2 + sta BSOUR1 + ;sta COUNT + #endif +END SUB diff --git a/demos/iec/kernal_load.lm b/demos/iec/kernal_load.lm new file mode 100644 index 0000000..7a362a7 --- /dev/null +++ b/demos/iec/kernal_load.lm @@ -0,0 +1,148 @@ +LOAD + ;******************************** + ;* C64 KERNAL IEEE LOAD ROUTINE * + ;******************************** + ;LOAD FROM CBM IEEE DEVICE + ; + LDY FNLEN ;MUST HAVE FILE NAME + BNE LD25 ;YES...OK + ; + JMP ERROR8 ;MISSING FILE NAME + ; +LD25 LDX SA ;SAVE SA IN .X + JSR LUKING ;TELL USER LOOKING + LDA #$60 ;SPECIAL LOAD COMMAND + STA SA + JSR OPENI ;OPEN THE FILE + ; + LDA FA + JSR TALK ;ESTABLISH THE CHANNEL + LDA SA + JSR TKSA ;TELL IT TO LOAD + ; + JSR ACPTR ;GET FIRST BYTE + STA EAL + ; + LDA STATUS ;TEST STATUS FOR ERROR + LSR + LSR + BCS LD90 ;FILE NOT FOUND... + JSR ACPTR ;GET SECOND BYTE + STA EAH + ; + TXA ;FIND OUT OLD SA + BNE LD30 ;SA<>0 USE DISK ADDRESS + LDA MEMUSS ;ELSE LOAD WHERE USER WANTS + STA EAL + LDA MEMUSS+1 + STA EAH +LD30 JSR LODING ;TELL USER LOADING + ; +LD40 LDA #$FD ;MASK OFF TIMEOUT + AND STATUS + STA STATUS + ; + ;JSR STOP ;STOP KEY? + ;BNE LD45 ;NO... + ; + ;JMP BREAK ;STOP KEY PRESSED + ; +LD45 JSR ACPTR ;GET BYTE OFF IEEE + TAX + LDA STATUS ;WAS THERE A TIMEOUT? + LSR + LSR + BCS LD40 ;YES...TRY AGAIN + TXA + LDY VERCK ;PERFORMING VERIFY? + BEQ LD50 ;NO...LOAD + LDY #0 + CMP (EAL),Y ;VERIFY IT + BEQ LD60 ;O.K.... + LDA #SPERR ;NO GOOD...VERIFY ERROR + JSR UDST ;UPDATE STATUS + .BYTE $2C ;SKIP NEXT STORE + ; +LD50 STA (EAL),Y +LD60 INC EAL ;INCREMENT STORE ADDR + BNE LD64 + INC EAH +LD64 BIT STATUS ;EOI? + BVC LD40 ;NO...CONTINUE LOAD + ; + JSR UNTLK ;CLOSE CHANNEL + JSR CLSEI ;CLOSE THE FILE + BCC LD180 ;BRANCH ALWAYS + ; +LD90 JMP ERROR4 ;FILE NOT FOUND + ; +OPENI LDA SA + BMI OP175 ;NO SA...DONE + + LDY FNLEN + BEQ OP175 ;NO FILE NAME...DONE + ; + LDA #0 ;CLEAR THE SERIAL STATUS + STA STATUS + ; + LDA FA + JSR LISTN ;DEVICE LA TO LISTEN + ; + LDA SA + ORA #$F0 + JSR SECND + ; + LDA STATUS ;ANYBODY HOME? + BPL OP35 ;YES...CONTINUE + ; + ;THIS ROUTINE IS CALLED BY OTHER + ;KERNAL ROUTINES WHICH ARE CALLED + ;DIRECTLY BY OS. KILL RETURN + ;ADDRESS TO RETURN TO OS. + ; + PLA + PLA + JMP ERROR5 ;DEVICE NOT PRESENT + ; +OP35 LDA FNLEN + BEQ OP45 ;NO NAME...DONE SEQUENCE + ; + ;SEND FILE NAME OVER SERIAL + ; + LDY #0 +OP40 LDA (FNADR),Y + JSR CIOUT + INY + CPY FNLEN + BNE OP40 + ; +OP45 JMP CUNLSN ;JSR UNLSN: CLC: RTS + ; +UDST ORA STATUS + STA STATUS + RTS + ; +CLSEI BIT SA + BMI CLSEI2 + LDA FA + JSR LISTN + LDA SA + AND #$EF + ORA #$E0 + JSR SECND + ; +CUNLSN JSR UNLSN ;ENTRY FOR OPENI + ; +CLSEI2 CLC + RTS + ; +LD180 CLC ;GOOD EXIT + ; + ; SET UP END LOAD ADDRESS + ; + LDX EAL + LDY EAH + ; +OP175 CLC ;FLAG GOOD OPEN +OP180 RTS ;EXIT IN PEACE + diff --git a/demos/iec/kernal_save.lm b/demos/iec/kernal_save.lm new file mode 100644 index 0000000..31e56cb --- /dev/null +++ b/demos/iec/kernal_save.lm @@ -0,0 +1,60 @@ +SAVE + LDA #$61 ; "OPEN" COMMAND CHANNEL 1 + STA SA + LDY FNLEN + BNE SV25 + ; + JMP ERROR8 ;MISSING FILE NAME + ; +SV25 JSR OPENI + JSR SAVING + LDA FA + JSR LISTN + LDA SA + JSR SECND + LDY #0 + JSR RD300 + LDA SAL + JSR CIOUT + LDA SAH + JSR CIOUT +SV30 JSR CMPSTE ;COMPARE START TO END + BCS SV50 ;HAVE REACHED END + LDA (SAL),Y + JSR CIOUT + ;JSR STOP + ;BNE SV40 + ; + ;BREAK JSR CLSEI + ; LDA #0 + ; SEC + ; RTS + ; +SV40 JSR INCSAL ;INCREMENT CURRENT ADDR. + BNE SV30 +SV50 JSR UNLSN + JSR CLSEI + ; + JMP CUNLSN + ; +RD300 LDA STAH ; RESTORE STARTING ADDRESS... + STA SAH ;...POINTERS (SAH & SAL) + LDA STAL + STA SAL + RTS + +;COMPARE START AND END LOAD/SAVE +;ADDRESSES. SUBROUTINE CALLED BY +;TAPE READ, SAVE, TAPE WRITE +; +CMPSTE SEC + LDA SAL + SBC EAL + LDA SAH + SBC EAH + RTS +; +INCSAL INC SAL + BNE INCR + INC SAH +INCR RTS diff --git a/demos/iec/kernal_serial.lm b/demos/iec/kernal_serial.lm new file mode 100644 index 0000000..d97b538 --- /dev/null +++ b/demos/iec/kernal_serial.lm @@ -0,0 +1,336 @@ +;adapted from https://github.com/mist64/cbmsrc/blob/master/KERNAL_C64_02/serial4.0 +;.PAG 'SERIAL ROUTINES' +;COMMAND SERIAL BUS DEVICE TO TALK +; +TALK ORA #$40 ;MAKE A TALK ADR + .BYTE $2C ;SKIP TWO BYTES +; +;COMMAND SERIAL BUS DEVICE TO LISTEN +; +LISTN ORA #$20 ;MAKE A LISTEN ADR + ; @@@ JSR RSP232 ;PROTECT SELF FROM RS232 NMI'S --- disabled +LIST1 PHA +; +; + BIT C3P0 ;CHARACTER LEFT IN BUF? + BPL LIST2 ;NO... +; +;SEND BUFFERED CHARACTER +; + SEC ;SET EOI FLAG + ROR R2D2 +; + JSR ISOUR ;SEND LAST CHARACTER +; + LSR C3P0 ;BUFFER CLEAR FLAG + LSR R2D2 ;CLEAR EOI FLAG +; +; +LIST2 PLA ;TALK/LISTEN ADDRESS + STA BSOUR + ; @@@ SEI + JSR DATAHI + CMP #$3F ;CLKHI ONLY ON UNLISTEN --- is this a bug? + BNE LIST5 + JSR CLKHI +; +LIST5 LDA D2PRA ;ASSERT ATTENTION + ORA #BIT_ATN_OUT + STA D2PRA +; +ISOURA NOP ; @@@ SEI + JSR CLKLO ;SET CLOCK LINE LOW + JSR DATAHI + JSR W1MS ;DELAY 1 MS +; +ISOUR NOP ; @@@ SEI ;NO IRQ'S ALLOWED + JSR DATAHI ;MAKE SURE DATA IS RELEASED + JSR DEBPIA ;DATA SHOULD BE LOW + BCS NODEV + JSR CLKHI ;CLOCK LINE HIGH + BIT R2D2 ;EOI FLAG TEST + BPL NOEOI +; DO THE EOI +ISR02 JSR DEBPIA ;WAIT FOR DATA TO GO HIGH + BCC ISR02 +; +ISR03 JSR DEBPIA ;WAIT FOR DATA TO GO LOW + BCS ISR03 +; +NOEOI JSR DEBPIA ;WAIT FOR DATA HIGH + BCC NOEOI + JSR CLKLO ;SET CLOCK LOW +; +; SET TO SEND DATA +; + LDA #$08 ;COUNT 8 BITS + STA COUNT +; +ISR01 + LDA D2PRA ;DEBOUNCE THE BUS + CMP D2PRA + BNE ISR01 + ASL A ;SET THE FLAGS + #ifdef APPLE1 then ASL + BCC FRMERR ;DATA MUST BE HI +; + ROR BSOUR ;NEXT BIT INTO CARRY + BCS ISRHI + JSR DATALO + BNE ISRCLK +ISRHI JSR DATAHI +ISRCLK JSR CLKHI ;CLOCK HI + NOP + NOP + NOP + NOP + LDA D2PRA + AND #$FF-BIT_DATA_OUT ;DATA HIGH + ORA #BIT_CLK_OUT ;CLOCK LOW + STA D2PRA + DEC COUNT + BNE ISR01 + +#ifdef C64 + LDA #$04 ;SET TIMER FOR 1MS + STA D1T2H + LDA #TIMRB ;TRIGGER TIMER + STA D1CRB ;--- timer starts here + LDA D1ICR ;CLEAR THE TIMER FLAGS<<<<<<<<<<<<< +ISR04 LDA D1ICR ;--- read timer flag + AND #$02 ;--- $02 is underflow timer B (ICR bit 1) + BNE FRMERR + JSR DEBPIA + BCS ISR04 +#endif + +#ifdef APPLE1 + LDA #$04 ;SET TIMER FOR 1MS + STA D2T2H ;--- timer starts here, flag cleared +ISR04 LDA D2IFR ;--- read timer flag + AND #$20 ;--- $20 is timer 2 (IFR bit 5) + BNE FRMERR + JSR DEBPIA + BCS ISR04 +#endif + + ; @@@ CLI ;LET IRQ'S CONTINUE + RTS +; +NODEV ;DEVICE NOT PRESENT ERROR + LDA #$80 + .BYTE $2C +FRMERR ;FRAMING ERROR + LDA #$03 +CSBERR JSR UDST ;COMMODORE SERIAL BUSS ERROR ENTRY + ; @@@ CLI ;IRQ'S WERE OFF...TURN ON + CLC ;MAKE SURE NO KERNAL ERR + BCC DLABYE ;TURN ATN OFF ,RELEASE ALL LINES +; +;SEND SECONDARY ADDRESS AFTER LISTEN +; +SECND STA BSOUR ;BUFFER CHARACTER + JSR ISOURA ;SEND IT +;RELEASE ATTENTION AFTER LISTEN +; +SCATN LDA D2PRA + AND #$FF-BIT_ATN_OUT + STA D2PRA ;RELEASE ATTENTION + RTS +;TALK SECOND ADDRESS +; +TKSA STA BSOUR ;BUFFER CHARACTER + JSR ISOURA ;SEND SECOND ADDR +TKATN ;SHIFT OVER TO LISTENER + ; @@@ SEI ;NO IRQ'S HERE + JSR DATALO ;DATA LINE LOW + JSR SCATN + JSR CLKHI ;CLOCK LINE HIGH JSR/RTS +TKATN1 JSR DEBPIA ;WAIT FOR CLOCK TO GO LOW + BMI TKATN1 + ; @@@ CLI ;IRQ'S OKAY NOW + RTS +;BUFFERED OUTPUT TO SERIAL BUS +; +CIOUT BIT C3P0 ;BUFFERED CHAR? + BMI CI2 ;YES...SEND LAST +; + SEC ;NO... + ROR C3P0 ;SET BUFFERED CHAR FLAG + BNE CI4 ;BRANCH ALWAYS +; +CI2 PHA ;SAVE CURRENT CHAR + JSR ISOUR ;SEND LAST CHAR + PLA ;RESTORE CURRENT CHAR +CI4 STA BSOUR ;BUFFER CURRENT CHAR + CLC ;CARRY-GOOD EXIT + RTS + +;SEND UNTALK COMMAND ON SERIAL BUS +; +UNTLK NOP ; @@@ SEI + JSR CLKLO + LDA D2PRA ;PULL ATN + ORA #BIT_ATN_OUT + STA D2PRA + LDA #$5F ;UNTALK COMMAND + .BYTE $2C ;SKIP TWO BYTES +;SEND UNLISTEN COMMAND ON SERIAL BUS +; +UNLSN LDA #$3F ;UNLISTEN COMMAND + JSR LIST1 ;SEND IT +; +; RELEASE ALL LINES +DLABYE JSR SCATN ;ALWAYS RELEASE ATN +; DELAY THEN RELEASE CLOCK AND DATA +; +DLADLH TXA ;DELAY APPROX 60 US + LDX #10 +DLAD00 DEX + BNE DLAD00 + TAX + JSR CLKHI + JMP DATAHI + +;INPUT A BYTE FROM SERIAL BUS +; +ACPTR + SEI ;NO IRQ ALLOWED + LDA #$00 ;SET EOI/ERROR FLAG + STA COUNT + JSR CLKHI ;MAKE SURE CLOCK LINE IS RELEASED +ACP00A JSR DEBPIA ;WAIT FOR CLOCK HIGH + BPL ACP00A + +#ifdef C64 +EOIACP + LDA #$01 ;SET TIMER 2 FOR 256US + STA D1T2H + LDA #TIMRB + STA D1CRB + JSR DATAHI ;DATA LINE HIGH (MAKES TIMMING MORE LIKE VIC-20 + LDA D1ICR ;CLEAR THE TIMER FLAGS<<<<<<<<<<<< +ACP00 LDA D1ICR + AND #$02 ;CHECK THE TIMER + BNE ACP00B ;RAN OUT..... + JSR DEBPIA ;CHECK THE CLOCK LINE + BMI ACP00 ;NO NOT YET + BPL ACP01 ;YES..... +#endif + +#ifdef APPLE1 +EOIACP LDA #$01 ;SET TIMER 2 FOR 256US + STA D2T2H + JSR DATAHI ;DATA LINE HIGH (MAKES TIMMING MORE LIKE VIC-20 +ACP00 LDA D2IFR + AND #$20 ;CHECK THE TIMER + BNE ACP00B ;RAN OUT..... + JSR DEBPIA ;CHECK THE CLOCK LINE + BMI ACP00 ;NO NOT YET + BPL ACP01 ;YES..... +#endif + +; +ACP00B LDA COUNT ;CHECK FOR ERROR (TWICE THRU TIMEOUTS) + BEQ ACP00C + LDA #2 + JMP CSBERR ; ST = 2 READ TIMEOUT +; +; TIMER RAN OUT DO AN EOI THING +; +ACP00C JSR DATALO ;DATA LINE LOW + JSR CLKHI ; DELAY AND THEN SET DATAHI (FIX FOR 40US C64) + LDA #$40 + JSR UDST ;OR AN EOI BIT INTO STATUS + INC COUNT ;GO AROUND AGAIN FOR ERROR CHECK ON EOI + BNE EOIACP +; +; DO THE BYTE TRANSFER +; +ACP01 LDA #8 ;SET UP COUNTER + STA COUNT +; +ACP03 LDA D2PRA ;WAIT FOR CLOCK HIGH + CMP D2PRA ;DEBOUNCE + BNE ACP03 + ASL A ;SHIFT DATA INTO CARRY + #ifdef APPLE1 then ASL + BPL ACP03 ;CLOCK STILL LOW... + ROR BSOUR1 ;ROTATE DATA IN +; +ACP03A LDA D2PRA ;WAIT FOR CLOCK LOW + CMP D2PRA ;DEBOUNCE + BNE ACP03A + ASL A + #ifdef APPLE1 then ASL + BMI ACP03A + DEC COUNT + BNE ACP03 ;MORE BITS..... +;...EXIT... + JSR DATALO ;DATA LOW + BIT STATUS ;CHECK FOR EOI + BVC ACP04 ;NONE... +; + JSR DLADLH ;DELAY THEN SET DATA HIGH +; +ACP04 LDA BSOUR1 + ; @@@ CLI ;IRQ IS OK + CLC ;GOOD EXIT + RTS +; +CLKHI ;SET CLOCK LINE HIGH (INVERTED) + LDA D2PRA + AND #$FF-BIT_CLK_OUT + STA D2PRA + RTS +; +CLKLO ;SET CLOCK LINE LOW (INVERTED) + LDA D2PRA + ORA #BIT_CLK_OUT + STA D2PRA + RTS +; +DATAHI ;SET DATA LINE HIGH (INVERTED) + LDA D2PRA + AND #$FF-BIT_DATA_OUT + STA D2PRA + RTS +; +DATALO ;SET DATA LINE LOW (INVERTED) + LDA D2PRA + ORA #BIT_DATA_OUT + STA D2PRA + RTS +; +DEBPIA LDA D2PRA ;DEBOUNCE THE PIA + CMP D2PRA + BNE DEBPIA + #ifdef APPLE1 then ASL + ASL A ;SHIFT THE DATA BIT INTO THE CARRY... + RTS ;...AND THE CLOCK INTO NEG FLAG +; +W1MS ;DELAY 1MS USING LOOP + TXA ;SAVE .X + LDX #200-16 ;1000US-(1000/500*8=#40US HOLDS) +W1MS1 DEX ;5US LOOP + BNE W1MS1 + TAX ;RESTORE .X + RTS +;.END +;******************************* +;WRITTEN 8/11/80 BOB FAIRBAIRN +;TEST SERIAL0.6 8/12/80 RJF +;CHANGE I/O STRUCTURE 8/21/80 RJF +;MORE I/O CHANGES 8/24/80 RJF +;FINAL RELEASE INTO KERNAL 8/26/80 RJF +;SOME CLEAN UP 9/8/80 RSR +;ADD IRQ PROTECT ON ISOUR AND TKATN 9/22/80 RSR +;FIX UNTALK 10/7/80 RSR +;MODIFY FOR VIC-40 I/O SYSTEM 12/08/81 RSR +;ADD SEI TO (UNTLK,ISOURA,LIST2) 12/14/81 RSR +;MODIFY FOR 6526 FLAGS FIX ERRS 12/31/81 RSR +;MODIFY FOR COMMODORE 64 I/O 3/11/82 RSR +;CHANGE ACPTR EOI FOR BETTER RESPONSE 3/28/82 RSR +;CHANGE WAIT 1 MS ROUTINE FOR LESS CODE 4/8/82 RSR +;****************************** +;.END diff --git a/demos/iec/m.bat b/demos/iec/m.bat new file mode 100644 index 0000000..74ee359 --- /dev/null +++ b/demos/iec/m.bat @@ -0,0 +1,18 @@ +@echo off + +set DASM=C:\Users\Nino1\Desktop\USB\compilers\dasm\dasm.exe +set ASMPROC=call asmproc +rem set ASMPROC=node ..\..\asmproc\dist\asmproc + +%ASMPROC% -i iec.lm -o iec.asm -t dasm -d APPLE1 +if %errorlevel% == -1 goto fine + +%DASM% iec.asm -f1 -liec.lst -oiec.prg +if %errorlevel% == -1 goto fine + +call node ..\..\tools\prg2bin.js -i iec.prg -o iec#060280 + +echo "ALL OK!" + +:fine + diff --git a/demos/iec/macros.lm b/demos/iec/macros.lm new file mode 100644 index 0000000..b33fe79 --- /dev/null +++ b/demos/iec/macros.lm @@ -0,0 +1,170 @@ +; +; Aliases +; + +MACRO poke mem, const + lda #{2} + sta {1} +END MACRO + +MACRO call mem + jsr {1} +END MACRO + +macro ret + rts +end macro + +macro push "a" + pha +end macro + +macro pop "a" + pla +end macro + +macro or mem + ora {1} +end macro + +macro or const + ora #{1} +end macro + +; +; Easy loads +; + +macro ld "a", mem + lda {2} +end macro + +macro ld "a", const + lda #{2} +end macro + +macro ld "a", indirect + ldy #0 + lda {2},y +end macro + +macro ld "x", mem + ldx {2} +end macro + +macro ld "x", const + ldx #{2} +end macro + +macro ld "y", mem + ldy {2} +end macro + +macro ld "y", const + ldy #{2} +end macro + +macro ld mem, "a" + sta {1} +end macro + +macro ld mem, "x" + stx {1} +end macro + +macro ld mem, "y" + sty {1} +end macro + +macro ld "a", "x" + txa +end macro + +macro ld "a", "y" + tya +end macro + +macro ld "x", "a" + tax +end macro + +macro ld "y", "a" + tay +end macro + +MACRO ld "ya", const + lda #(({2}) MOD 256) + ldy #(({2})/256) +END MACRO + +MACRO ld "ya", mem + lda {1} + ldy {1}+1 +END MACRO + +macro ld mem, mem + lda {2} + sta {1} +end macro + +macro ld mem, const + lda #{2} + sta {1} +end macro + +macro ld indirect, "a" + ldy #0 + sta {1},y +end macro + +; +; Easy add and sub +; + +MACRO add mem + clc + adc {1} +END MACRO + +MACRO add const + clc + adc #{1} +END MACRO + +MACRO add mem, const + clc + lda {1} + adc #{2} + sta {1} +END MACRO + +MACRO add mem, mem + clc + lda {1} + adc {2} + sta {1} +END MACRO + +MACRO sub mem + sec + sbc {1} +END MACRO + +MACRO sub const + sec + sbc #{1} +END MACRO + +MACRO sub mem, const + sec + lda {1} + sbc #{2} + sta {1} +END MACRO + +MACRO sub mem, mem + sec + lda {1} + sbc {2} + sta {1} +END MACRO diff --git a/demos/iec/macros_16.lm b/demos/iec/macros_16.lm new file mode 100644 index 0000000..e720ffd --- /dev/null +++ b/demos/iec/macros_16.lm @@ -0,0 +1,271 @@ +; ====================================================== +; Macros for 16 bit operations +; The suffix "16" is added to common opcodes, eg "add16" +; Only the A register is used (except ld16 (indirect)) +; ====================================================== + +; Summary +; add16, adc16 +; sub16, sbc16 +; inc16, dec16 +; ld16 +; cmp16 +; shr16, shl16 +; push16, pop16 + +macro add16 mem, const + lda {1} + clc + adc #(({2}) MOD 256) + sta {1} + lda {1}+1 + #if {2} < 256 + if carry then inc {1}+1 + #else + adc #(({2})/256) + sta {1}+1 + #endif +end macro + +macro add16 mem, mem + lda {1} + clc + adc {2} + sta {1} + lda {1}+1 + adc {2}+1 + sta {1}+1 +end macro + +macro add16 mem, const, "1" + lda {1} + sec + adc #(({2}) MOD 256) + sta {1} + lda {1}+1 + adc #({2}/256) + sta {1}+1 +end macro + +macro add16 mem, mem, "1" + lda {1} + sec + adc {2} + sta {1} + lda {1}+1 + adc {2}+1 + sta {1}+1 +end macro + +macro adc16 mem, const + lda {1} + adc #(({2}) MOD 256) + sta {1} + lda {1}+1 + #if {2} < 256 + bcc .local_out + inc {1}+1 + #else + adc #(({2})/256) + sta {1}+1 + #endif + .local_out: +end macro + +macro adc16 mem, mem + lda {1} + adc {2} + sta {1} + lda {1}+1 + adc {2}+1 + sta {1}+1 +end macro + +macro sub16 mem, const + lda {1} + sec + sbc #(({2}) MOD 256) + sta {1} + lda {1}+1 + sbc #(({2})/256) + sta {1}+1 +end macro + +macro sub16 mem, mem + lda {1} + sec + sbc {2} + sta {1} + lda {1}+1 + sbc {2}+1 + sta {1}+1 +end macro + +macro sub16 mem, const, "1" + lda {1} + clc + sbc #(({2}) MOD 256) + sta {1} + lda {1}+1 + sbc #(({2})/256) + sta {1}+1 +end macro + +macro sub16 mem, mem, "1" + lda {1} + clc + sbc {2} + sta {1} + lda {1}+1 + sbc {2}+1 + sta {1}+1 +end macro + +macro sbc16 mem, const + lda {1} + sbc #(({2}) MOD 256) + sta {1} + lda {1}+1 + sbc #(({2})/256) + sta {1}+1 +end macro + +macro sbc16 mem, mem + lda {1} + sbc {2} + sta {1} + lda {1}+1 + sbc {2}+1 + sta {1}+1 +end macro + +macro inc16 mem + inc {1} + if zero then inc {1}+1 +end macro + +macro dec16 mem + dec {1} + if negative then dec {1}+1 +end macro + +macro ld16 "ay", const + lda #(({2}) MOD 256) + ldy #(({2})/256) +end macro + +macro ld16 "ay", mem + lda {2} + ldy {2}+1 +end macro + +macro ld16 "ax", const + lda #(({2}) MOD 256) + ldx #(({2})/256) +end macro + +macro ld16 "ax", mem + lda {2} + ldx {2}+1 +end macro + +macro ld16 mem, "ay" + sta {1} + sty {1}+1 +end macro + +macro ld16 mem, "ax" + sta {1} + stx {1}+1 +end macro + +macro ld16 mem, const + lda #(({2}) MOD 256) + sta {1} + #if (({2}) MOD 256) != (({2})/256) + lda #(({2})/256) + #endif + sta {1}+1 +end macro + +macro ld16 mem, mem + lda {2} + sta {1} + lda {2}+1 + sta {1}+1 +end macro + +macro ld16 indirect, mem + ldy #0 + lda {2} + sta ({1}),y + lda {2}+1 + iny + sta ({1}),y +end macro + +macro ld16 indirect, const + ldy #0 + lda #({2} MOD 256) + sta ({1}),y + lda #({2}/256) + iny + sta ({1}),y +end macro + +macro cmp16 mem, const + lda {1}+1 + cmp #(({2})/256) + if zero then + lda {1} + cmp #(({2}) MOD 256) + end if +end macro + +macro cmp16 mem, mem + lda {1}+1 + cmp {2}+1 + if zero then + lda {1} + cmp {2} + end if +end macro + +macro shl16 mem + asl {1} + rol {1}+1 +end macro + +macro shr16 mem + lsr {1} + ror {1}+1 +end macro + +macro push16 mem + lda {1} + pha + lda {1}+1 + pha +end macro + +macro push16 const + lda #(({1}) MOD 256) + pha + lda #(({1})/256) + pha +end macro + +macro pop16 mem + pla + sta {1}+1 + pla + sta {1} +end macro + +macro mul16 mem, const + ECHO "to be implemented" +end macro + +macro mul16 mem, mem + ECHO "to be implemented" +end macro diff --git a/demos/iec/read_file.lm b/demos/iec/read_file.lm new file mode 100644 index 0000000..fb36e07 --- /dev/null +++ b/demos/iec/read_file.lm @@ -0,0 +1,105 @@ +// +// this is an example of reading a file with the high-level kernal routines +// + +/* +basic start + 5 POKE 36879,8:PRINT "{clr}{wht}"; + 6 REM the ReadFile() function does something like this: + 10 LA=7680 + 20 OPEN 1,8,2,"iec" + 30 IF ST<>0 THEN GOTO 60 + 40 GET#1,A$:IF A$="" THEN A$=CHR$(0) + 50 POKE LA,ASC(A$):LA=LA+1:GOTO 30 + 60 CLOSE 1 +basic end +*/ + +basic start + 5 POKE 36879,8:PRINT "{clr}{wht}"; + 10 print "{down}{down}{down}{down}{down}{down}{down}{down}{down}{down}disk drive test" + 20 sys {main} +basic end + +main: + call ReadFile + rts + +const SETNAM = $FFBD ; Kernal Set Filename +const SETLFS = $FFBA ; Kernal Set Logical First and Secondary +const ICHKIN = $FFC6 ; Kernal Set Input +const READST = $FFB7 ; Kernal read status byte +const ICHRIN = $FFCF ; Kernal read a byte from file +const ICLOSE = $FFC3 ; Kernal close +const ICLRCH = $FFCC ; Kernal clear channel + +#ifdef C64 + const load_address = 1024 +#endif + +#ifdef VIC20 + const load_address = 7680 +#endif + +sub ReadFile() + ld16 $ae, #load_address ; destination buffer + + LDA #fname_end-fname + LDX #fname + JSR SETNAM + + LDA #$02 ; file number 2 + LDX #$08 ; default to device 8 + LDY #$02 ; secondary address 2 + JSR $FFBA ; call SETLFS + JSR $FFC0 ; call OPEN + + ; check if the file could not be opened + if carry then + jsr open_error ; handle open error + jmp close ; even if OPEN failed, the file has to be closed + end if + + LDX #$02 ; filenumber 2 + JSR ICHKIN ; file 2 now used as input + + LDY #$00 ; keep y indexing at 0 + do + JSR READST ; read status byte + if not zero then exit do ; either EOF or read error + JSR ICHRIN ; get a byte from file + STA ($AE),Y ; write byte to memory + inc16 $ae ; increment pointer + loop while not zero + + AND #$40 ; end of file? + if zero then jsr read_error + +close: + LDA #$02 ; filenumber 2 + JSR ICLOSE + JSR ICLRCH + RTS + +open_error: + ; Akkumulator contains BASIC error code + ; most likely errors: + ; A = $05 (DEVICE NOT PRESENT) + ;... error handling for open errors ... + lda #00 + sta load_address + rts + +read_error: + ; for further information, the drive error channel has to be read + ;... error handling for read errors ... + lda #01 + sta load_address + rts +end sub + +fname: + byte "iec" +fname_end: + diff --git a/demos/iec/x.lm b/demos/iec/x.lm new file mode 100644 index 0000000..96398dd --- /dev/null +++ b/demos/iec/x.lm @@ -0,0 +1,39 @@ +basic start + 100 print "{wht}saving file" + 110 sys {save_file} + 120 GOSUB 2000:rem stampa ST + 130 gosub 1000:rem read file with basic + 140 gosub 200:rem read file with lm + 150 end + + 200 rem ============================= + 205 print "loading file at $2000" + 210 sys {load_file} + 220 print "load ok" + 230 l={file_content_end}-{file_content_start} + 240 for t=0 to l-1 + 250 poke 1024+t,peek(8192+t) + 260 next + 270 return + + 1000 rem ======================== + 1005 REM reads the file "prova" + 1006 print "reading back file" + 1007 C=0 + 1010 OPEN 1,8,2,"prova" + 1020 IF ST<>0 THEN GOTO 1050 + 1030 GET#1,A$:IF A$="" THEN A$=CHR$(0) + 1040 PRINT A$;:C=C+1:GOTO 1020 + 1050 PRINT:GOSUB 2000 + 1055 PRINT "bytes=";C + 1060 CLOSE 1 + 1070 RETURN + + 2000 PRINT "st=";ST; + 2001 IF (ST AND 2)<>0 THEN PRINT "timeout "; + 2010 IF (ST AND 16)<>0 THEN PRINT "verify error"; + 2020 IF (ST AND 64)<>0 THEN PRINT "eof "; + 2030 IF (ST AND 128)<>0 THEN PRINT "device not present "; + 2035 PRINT + 2040 RETURN +basic end