Update telestrat target doc, add tgi_clear support for telestrat target, stratsed & telemon 2.4 vars added
;------------------------------------------------------------------------------
; The mouse API version, stored in MOUSE_HDR::VERSION
-MOUSE_API_VERSION = $05
+MOUSE_API_VERSION = $06
;------------------------------------------------------------------------------
; Bitmapped mouse driver flags, stored in MOUSE_HDR::FLAGS.
ldy #opcode
sty _SMCDesignator
.else
- .error "Invalid usage of macro 'SMC_TransferOpcode'"
+ .error "Invalid usage of macro 'SMC_TransferOpcode'"
.endif
.endmacro
.elseif .match ({register}, y)
ldy _SMCDesignator
.else
- .error "Invalid usage of macro 'SMC_LoadOpcode'"
+ .error "Invalid usage of macro 'SMC_LoadOpcode'"
.endif
.endmacro
.elseif .match ({register}, y)
sty _SMCDesignator
.else
- .error "Invalid usage of macro 'SMC_StoreOpcode'"
+ .error "Invalid usage of macro 'SMC_StoreOpcode'"
.endif
.endmacro
ldy #(<(destination - _SMCDesignator - 2))
sty _SMCDesignator+1
.else
- .error "Invalid usage of macro 'SMC_ChangeBranch'"
+ .error "Invalid usage of macro 'SMC_ChangeBranch'"
.endif
.endmacro
ldy value
sty _SMCDesignator+1
.else
- .error "Invalid usage of macro 'SMC_TransferValue'"
+ .error "Invalid usage of macro 'SMC_TransferValue'"
.endif
.endmacro
.elseif .match ({register}, y)
ldy _SMCDesignator+1
.else
- .error "Invalid usage of macro 'SMC_LoadValue'"
+ .error "Invalid usage of macro 'SMC_LoadValue'"
.endif
.endmacro
.elseif .match ({register}, y)
sty _SMCDesignator+1
.else
- .error "Invalid usage of macro 'SMC_StoreValue'"
+ .error "Invalid usage of macro 'SMC_StoreValue'"
.endif
.endmacro
ldy value
sty _SMCDesignator+2
.else
- .error "Invalid usage of macro 'SMC_TransferHighByte'"
+ .error "Invalid usage of macro 'SMC_TransferHighByte'"
.endif
.endmacro
.elseif .match ({register}, y)
ldy _SMCDesignator+2
.else
- .error "Invalid usage of macro 'SMC_LoadHighByte'"
+ .error "Invalid usage of macro 'SMC_LoadHighByte'"
.endif
.endmacro
.elseif .match ({register}, y)
sty _SMCDesignator+2
.else
- .error "Invalid usage of macro 'SMC_StoreHighByte'"
+ .error "Invalid usage of macro 'SMC_StoreHighByte'"
.endif
.endmacro
sty _SMCDesignator+2
.endif
.else
- .error "Invalid usage of macro 'SMC_TransferAddressSingle'"
+ .error "Invalid usage of macro 'SMC_TransferAddressSingle'"
.endif
.endmacro
; MACRO
.macro BRK_TELEMON value
- .byte $00,value
+ .byte $00,value
.endmacro
--- /dev/null
+FEATURES {
+ STARTADDRESS: default = $2E00;
+}
+SYMBOLS {
+ __STARTADDRESS__: type = export, value = %S;
+}
+MEMORY {
+ ZP: file = "", define = yes, start = $0082, size = $007E;
+ MAIN: file = %O, define = yes, start = %S, size = $BC20 - %S;
+}
+FILES {
+ %O: format = atari;
+}
+FORMATS {
+ atari: runad = start;
+}
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp, optional = yes;
+ EXTZP: load = ZP, type = zp, optional = yes; # to enable modules to be able to link to C and assembler programs
+ CODE: load = MAIN, type = rw, define = yes;
+ RODATA: load = MAIN, type = ro optional = yes;
+ DATA: load = MAIN, type = rw optional = yes;
+ BSS: load = MAIN, type = bss, optional = yes, define = yes;
+}
__ORIXHDR__: type = import;
__STACKSIZE__: type = weak, value = $0800; # 2K stack
__GRAB__: type = weak, value = 0; # 0=don't grab graphics RAM, 1=grab graphics RAM
- __RAMEND__: type = weak, value = $9800 + $1C00 * __GRAB__;
+ __RAMEND__: type = weak, value = $9800 + $1C00 * __GRAB__;
}
MEMORY {
ZP: file = "", define = yes, start = $00B0, size = $003A;
The values you assign to the two symbols <tt/__AUTOSTART__/ and <tt/__EXEHDR__/
don't matter.
+<sect2><tt/atari-xex.cfg/<p>
+
+This config file allows writing multi segment binaries easily, without having to
+write the header explicitly on each segment.
+
+It is similar to the <tt/atari-asm.cfg/ above, but uses the ATARI (xex) file
+format support on LD65 instead of the standard binary output, so it does not
+have the <tt/__AUTOSTART/ nor the <tt/__EXEHDR__/ symbols.
+
+Note that each <tt/MEMORY/ area in the configuration file will have it's own
+segment in the output file with the correct headers.
+
<sect2><tt/atari-cart.cfg/<p>
This config file can be used to create 8K or 16K cartridges. It's suited both
Allow C-style backslash escapes within string constants to embed
special characters. The following escapes are accepted:
-
-<itemize>
-<item><tt>\\</tt> backslash (<tt>$5C</tt>)
-<item><tt>\'</tt> single quote (<tt>$27</tt>)
-<item><tt>\"</tt> double quote (<tt>$22</tt>)
-<item><tt>\t</tt> tab (<tt>$09</tt>)
-<item><tt>\r</tt> carriage return (<tt>$0D</tt>)
-<item><tt>\n</tt> newline (<tt>$0A</tt>)
-<item><tt>\xNN</tt> (<tt>$NN</tt>)
-</itemize>
-
- Note that <tt>\n</tt> maps to ASCII <tt>$0A</tt>, not a platform specific
- line ending character.
+ <itemize>
+ <item><tt>\\</tt> backslash (<tt>$5C</tt>)
+ <item><tt>\'</tt> single quote (<tt>$27</tt>)
+ <item><tt>\"</tt> double quote (<tt>$22</tt>)
+ <item><tt>\t</tt> tab (<tt>$09</tt>)
+ <item><tt>\r</tt> carriage return (<tt>$0D</tt>)
+ <item><tt>\n</tt> newline (<tt>$0A</tt>)
+ <item><tt>\xNN</tt> (<tt>$NN</tt>)
+ </itemize>
+
+ Note that string escapes are converted to platform-specific characters in
+ the same way that other characters are converted.
<tag><tt>ubiquitous_idents</tt><label id="ubiquitous_idents"></tag>
}
</verb></tscreen>
-The only other available output format is the o65 format specified by Andre
+There are two other available formats, one is the o65 format specified by Andre
Fachat (see the <url url="http://www.6502.org/users/andre/o65/fileformat.html"
name="6502 binary relocation format specification">). It is defined like this:
}
</verb></tscreen>
-The necessary o65 attributes are defined in a special section labeled
+The other format available is the Atari (xex) segmented file format, this is
+the standard format used by Atari DOS 2.0 and upward file managers in the Atari
+8-bit computers, and it is defined like this:
+
+<tscreen><verb>
+ FILES {
+ %O: format = atari;
+ }
+</verb></tscreen>
+
+In the Atari segmented file format, the linker will write each <tt/MEMORY/ area
+as a new segment, including a header with the start and end address.
+
+The necessary o65 or Atari attributes are defined in a special section labeled
<ref id="FORMAT" name="FORMAT">.
}
</verb></tscreen>
+The Atari file format has only one attribute, <tt/RUNAD/ that allows to specify
+a symbol as the run address of the binary. If the attribute is omiteed, no run
+address is specified.
+
+<tscreen><verb>
+ FORMATS {
+ atari: runad = _start;
+ }
+</verb></tscreen>
<sect1>The FEATURES section<label id="FEATURES"><p>
/* TIA write / read registers */
struct __tia {
union {
- unsigned char vsync;
- unsigned char cxm0p;
+ unsigned char vsync;
+ unsigned char cxm0p;
};
union {
- unsigned char vblank;
- unsigned char cxm1p;
+ unsigned char vblank;
+ unsigned char cxm1p;
};
union {
- unsigned char wsync;
- unsigned char cxp0fb;
+ unsigned char wsync;
+ unsigned char cxp0fb;
};
union {
- unsigned char rsync;
- unsigned char cxp1fb;
+ unsigned char rsync;
+ unsigned char cxp1fb;
};
union {
- unsigned char nusiz0;
- unsigned char cxm0fb;
+ unsigned char nusiz0;
+ unsigned char cxm0fb;
};
union {
- unsigned char nusiz1;
- unsigned char cxm1fb;
+ unsigned char nusiz1;
+ unsigned char cxm1fb;
};
union {
- unsigned char colup0;
- unsigned char cxblpf;
+ unsigned char colup0;
+ unsigned char cxblpf;
};
union {
- unsigned char colup1;
- unsigned char cxppmm;
+ unsigned char colup1;
+ unsigned char cxppmm;
};
union {
- unsigned char colupf;
- unsigned char inpt0;
+ unsigned char colupf;
+ unsigned char inpt0;
};
union {
- unsigned char colubk;
- unsigned char inpt1;
+ unsigned char colubk;
+ unsigned char inpt1;
};
union {
- unsigned char ctrlpf;
- unsigned char inpt2;
+ unsigned char ctrlpf;
+ unsigned char inpt2;
};
union {
- unsigned char refp0;
- unsigned char inpt3;
+ unsigned char refp0;
+ unsigned char inpt3;
};
union {
- unsigned char refp1;
- unsigned char inpt4;
+ unsigned char refp1;
+ unsigned char inpt4;
};
union {
- unsigned char pf0;
- unsigned char inpt5;
+ unsigned char pf0;
+ unsigned char inpt5;
};
unsigned char pf1;
unsigned char pf2;
--- /dev/null
+/*****************************************************************************/
+/* */
+/* c64_screen_charmap.h */
+/* */
+/* (c) Copyright 2019, Gerhard W. Gruber (sparhawk@gmx.at) */
+/* */
+/* When using C64 mode, this include converts the characters */
+/* from PETSCII to screen mapping, so you can write directly to */
+/* the screen memory. */
+/* */
+/* If this include is used, no additional macros are needed */
+/* */
+/*****************************************************************************/
+
+/* No include guard here! Multiple use in one file may be intentional. */
+
+// Char $00 ... $1F -> c + 128
+#pragma warn (remap-zero, push, off)
+#pragma charmap ($00, $80)
+#pragma warn (remap-zero, pop)
+
+#pragma charmap ($01, $81)
+#pragma charmap ($02, $82)
+#pragma charmap ($03, $83)
+#pragma charmap ($04, $84)
+#pragma charmap ($05, $85)
+#pragma charmap ($06, $86)
+#pragma charmap ($07, $87)
+#pragma charmap ($08, $88)
+#pragma charmap ($09, $89)
+#pragma charmap ($0A, $8A)
+#pragma charmap ($0B, $8B)
+#pragma charmap ($0C, $8C)
+#pragma charmap ($0D, $8D)
+#pragma charmap ($0E, $8E)
+#pragma charmap ($0F, $8F)
+#pragma charmap ($10, $90)
+#pragma charmap ($11, $91)
+#pragma charmap ($12, $92)
+#pragma charmap ($13, $93)
+#pragma charmap ($14, $94)
+#pragma charmap ($15, $95)
+#pragma charmap ($16, $96)
+#pragma charmap ($17, $97)
+#pragma charmap ($18, $98)
+#pragma charmap ($19, $99)
+#pragma charmap ($1A, $9A)
+#pragma charmap ($1B, $9B)
+#pragma charmap ($1C, $9C)
+#pragma charmap ($1D, $9D)
+#pragma charmap ($1E, $9E)
+#pragma charmap ($1F, $9F)
+
+// Char $20 ... $3F -> c = c
+#pragma charmap ($20, $20)
+#pragma charmap ($21, $21)
+#pragma charmap ($22, $22)
+#pragma charmap ($23, $23)
+#pragma charmap ($24, $24)
+#pragma charmap ($25, $25)
+#pragma charmap ($26, $26)
+#pragma charmap ($27, $27)
+#pragma charmap ($28, $28)
+#pragma charmap ($29, $29)
+#pragma charmap ($2A, $2A)
+#pragma charmap ($2B, $2B)
+#pragma charmap ($2C, $2C)
+#pragma charmap ($2D, $2D)
+#pragma charmap ($2E, $2E)
+#pragma charmap ($2F, $2F)
+#pragma charmap ($30, $30)
+#pragma charmap ($31, $31)
+#pragma charmap ($32, $32)
+#pragma charmap ($33, $33)
+#pragma charmap ($34, $34)
+#pragma charmap ($35, $35)
+#pragma charmap ($36, $36)
+#pragma charmap ($37, $37)
+#pragma charmap ($38, $38)
+#pragma charmap ($39, $39)
+#pragma charmap ($3A, $3A)
+#pragma charmap ($3B, $3B)
+#pragma charmap ($3C, $3C)
+#pragma charmap ($3D, $3D)
+#pragma charmap ($3E, $3E)
+#pragma charmap ($3F, $3F)
+
+// Char $40 ... $5F -> c - 64
+#pragma charmap ($40, $00)
+#pragma charmap ($41, $01)
+#pragma charmap ($42, $02)
+#pragma charmap ($43, $03)
+#pragma charmap ($44, $04)
+#pragma charmap ($45, $05)
+#pragma charmap ($46, $06)
+#pragma charmap ($47, $07)
+#pragma charmap ($48, $08)
+#pragma charmap ($49, $09)
+#pragma charmap ($4A, $0A)
+#pragma charmap ($4B, $0B)
+#pragma charmap ($4C, $0C)
+#pragma charmap ($4D, $0D)
+#pragma charmap ($4E, $0E)
+#pragma charmap ($4F, $0F)
+#pragma charmap ($50, $10)
+#pragma charmap ($51, $11)
+#pragma charmap ($52, $12)
+#pragma charmap ($53, $13)
+#pragma charmap ($54, $14)
+#pragma charmap ($55, $15)
+#pragma charmap ($56, $16)
+#pragma charmap ($57, $17)
+#pragma charmap ($58, $18)
+#pragma charmap ($59, $19)
+#pragma charmap ($5A, $1A)
+#pragma charmap ($5B, $1B)
+#pragma charmap ($5C, $1C)
+#pragma charmap ($5D, $1D)
+#pragma charmap ($5E, $1E)
+#pragma charmap ($5F, $1F)
+
+// Char $60 ... $7F -> c - 32
+#pragma charmap ($60, $40)
+#pragma charmap ($61, $41)
+#pragma charmap ($62, $42)
+#pragma charmap ($63, $43)
+#pragma charmap ($64, $44)
+#pragma charmap ($65, $45)
+#pragma charmap ($66, $46)
+#pragma charmap ($67, $47)
+#pragma charmap ($68, $48)
+#pragma charmap ($69, $49)
+#pragma charmap ($6A, $4A)
+#pragma charmap ($6B, $4B)
+#pragma charmap ($6C, $4C)
+#pragma charmap ($6D, $4D)
+#pragma charmap ($6E, $4E)
+#pragma charmap ($6F, $4F)
+#pragma charmap ($70, $50)
+#pragma charmap ($71, $51)
+#pragma charmap ($72, $52)
+#pragma charmap ($73, $53)
+#pragma charmap ($74, $54)
+#pragma charmap ($75, $55)
+#pragma charmap ($76, $56)
+#pragma charmap ($77, $57)
+#pragma charmap ($78, $58)
+#pragma charmap ($79, $59)
+#pragma charmap ($7A, $5A)
+#pragma charmap ($7B, $5B)
+#pragma charmap ($7C, $5C)
+#pragma charmap ($7D, $5D)
+#pragma charmap ($7E, $5E)
+#pragma charmap ($7F, $5F)
+
+// Char $80 ... $9F -> c + 64
+#pragma charmap ($80, $C0)
+#pragma charmap ($81, $C1)
+#pragma charmap ($82, $C2)
+#pragma charmap ($83, $C3)
+#pragma charmap ($84, $C4)
+#pragma charmap ($85, $C5)
+#pragma charmap ($86, $C6)
+#pragma charmap ($87, $C7)
+#pragma charmap ($88, $C8)
+#pragma charmap ($89, $C9)
+#pragma charmap ($8A, $CA)
+#pragma charmap ($8B, $CB)
+#pragma charmap ($8C, $CC)
+#pragma charmap ($8D, $CD)
+#pragma charmap ($8E, $CE)
+#pragma charmap ($8F, $CF)
+#pragma charmap ($90, $D0)
+#pragma charmap ($91, $D1)
+#pragma charmap ($92, $D2)
+#pragma charmap ($93, $D3)
+#pragma charmap ($94, $D4)
+#pragma charmap ($95, $D5)
+#pragma charmap ($96, $D6)
+#pragma charmap ($97, $D7)
+#pragma charmap ($98, $D8)
+#pragma charmap ($99, $D9)
+#pragma charmap ($9A, $DA)
+#pragma charmap ($9B, $DB)
+#pragma charmap ($9C, $DC)
+#pragma charmap ($9D, $DD)
+#pragma charmap ($9E, $DE)
+#pragma charmap ($9F, $DF)
+
+// Char $A0 ... $BF -> c - 64
+#pragma charmap ($A0, $60)
+#pragma charmap ($A1, $61)
+#pragma charmap ($A2, $62)
+#pragma charmap ($A3, $63)
+#pragma charmap ($A4, $64)
+#pragma charmap ($A5, $65)
+#pragma charmap ($A6, $66)
+#pragma charmap ($A7, $67)
+#pragma charmap ($A8, $68)
+#pragma charmap ($A9, $69)
+#pragma charmap ($AA, $6A)
+#pragma charmap ($AB, $6B)
+#pragma charmap ($AC, $6C)
+#pragma charmap ($AD, $6D)
+#pragma charmap ($AE, $6E)
+#pragma charmap ($AF, $6F)
+#pragma charmap ($B0, $70)
+#pragma charmap ($B1, $71)
+#pragma charmap ($B2, $72)
+#pragma charmap ($B3, $73)
+#pragma charmap ($B4, $74)
+#pragma charmap ($B5, $75)
+#pragma charmap ($B6, $76)
+#pragma charmap ($B7, $77)
+#pragma charmap ($B8, $78)
+#pragma charmap ($B9, $79)
+#pragma charmap ($BA, $7A)
+#pragma charmap ($BB, $7B)
+#pragma charmap ($BC, $7C)
+#pragma charmap ($BD, $7D)
+#pragma charmap ($BE, $7E)
+#pragma charmap ($BF, $7F)
+
+// Char $C0 ... $DF -> c - 128
+#pragma charmap ($C0, $40)
+#pragma charmap ($C1, $41)
+#pragma charmap ($C2, $42)
+#pragma charmap ($C3, $43)
+#pragma charmap ($C4, $44)
+#pragma charmap ($C5, $45)
+#pragma charmap ($C6, $46)
+#pragma charmap ($C7, $47)
+#pragma charmap ($C8, $48)
+#pragma charmap ($C9, $49)
+#pragma charmap ($CA, $4A)
+#pragma charmap ($CB, $4B)
+#pragma charmap ($CC, $4C)
+#pragma charmap ($CD, $4D)
+#pragma charmap ($CE, $4E)
+#pragma charmap ($CF, $4F)
+#pragma charmap ($D0, $50)
+#pragma charmap ($D1, $51)
+#pragma charmap ($D2, $52)
+#pragma charmap ($D3, $53)
+#pragma charmap ($D4, $54)
+#pragma charmap ($D5, $55)
+#pragma charmap ($D6, $56)
+#pragma charmap ($D7, $57)
+#pragma charmap ($D8, $58)
+#pragma charmap ($D9, $59)
+#pragma charmap ($DA, $5A)
+#pragma charmap ($DB, $5B)
+#pragma charmap ($DC, $5C)
+#pragma charmap ($DD, $5D)
+#pragma charmap ($DE, $5E)
+#pragma charmap ($DF, $5F)
+
+// Char $E0 ... $FE -> c - 128
+#pragma charmap ($E0, $60)
+#pragma charmap ($E1, $61)
+#pragma charmap ($E2, $62)
+#pragma charmap ($E3, $63)
+#pragma charmap ($E4, $64)
+#pragma charmap ($E5, $65)
+#pragma charmap ($E6, $66)
+#pragma charmap ($E7, $67)
+#pragma charmap ($E8, $68)
+#pragma charmap ($E9, $69)
+#pragma charmap ($EA, $6A)
+#pragma charmap ($EB, $6B)
+#pragma charmap ($EC, $6C)
+#pragma charmap ($ED, $6D)
+#pragma charmap ($EE, $6E)
+#pragma charmap ($EF, $6F)
+#pragma charmap ($F0, $70)
+#pragma charmap ($F1, $71)
+#pragma charmap ($F2, $72)
+#pragma charmap ($F3, $73)
+#pragma charmap ($F4, $74)
+#pragma charmap ($F5, $75)
+#pragma charmap ($F6, $76)
+#pragma charmap ($F7, $77)
+#pragma charmap ($F8, $78)
+#pragma charmap ($F9, $79)
+#pragma charmap ($FA, $7A)
+#pragma charmap ($FB, $7B)
+#pragma charmap ($FC, $7C)
+#pragma charmap ($FD, $7D)
+#pragma charmap ($FE, $7E)
+#pragma charmap ($FF, $5E)
irq_enabled: .res 1 ; flag indicating that the high frequency polling interrupt is enabled
old_porta_vbi: .res 1 ; previous PORTA value of the VBI interrupt (IRQ)
how_long: .res 1 ; counter for how many VBI interrupts the mouse hasn't been moved
+in_irq: .res 1 ; flag indicating high-frequency polling interrupt is active
.if .defined (AMIGA_MOUSE) .or .defined (ST_MOUSE)
dumx: .res 1
.endif
.ifndef __ATARIXL__
-OldT1: .res 2
+OldT2: .res 2
.else
.data
-set_VTIMR1_handler:
+set_VTIMR2_handler:
.byte $4C, 0, 0
.endif
; Setup pointer to wrapper install/deinstall function.
lda libref
- sta set_VTIMR1_handler+1
+ sta set_VTIMR2_handler+1
lda libref+1
- sta set_VTIMR1_handler+2
+ sta set_VTIMR2_handler+2
; Install my handler.
sec
- lda #<T1Han
- ldx #>T1Han
- jsr set_VTIMR1_handler
+ lda #<T2Han
+ ldx #>T2Han
+ jsr set_VTIMR2_handler
.else
- lda VTIMR1
- sta OldT1
- lda VTIMR1+1
- sta OldT1+1
+ lda VTIMR2
+ sta OldT2
+ lda VTIMR2+1
+ sta OldT2+1
php
sei
- lda #<T1Han
- sta VTIMR1
- lda #>T1Han
- sta VTIMR1+1
+ lda #<T2Han
+ sta VTIMR2
+ lda #>T2Han
+ sta VTIMR2+1
plp
.endif
sta AUDCTL
lda #0
- sta AUDC1
+ sta AUDC2
lda #15
- sta AUDF1
+ sta AUDF2
sta STIMER
-.if 0 ; the IRQ will now be dynamically enabled when the mouse is moved
- lda POKMSK
- ora #%00000001 ; timer 1 enable
- sta POKMSK
- sta IRQEN
- sta irq_enabled
-.endif
-
lda PORTA
and #$0f
sta old_porta_vbi
; uninstall timer irq routine
lda POKMSK
- and #%11111110 ; timer 1 disable
+ and #%11111101 ; timer 2 disable
sta IRQEN
sta POKMSK
.ifdef __ATARIXL__
clc
- jsr set_VTIMR1_handler
+ jsr set_VTIMR2_handler
.else
php
sei
- lda OldT1
- sta VTIMR1
- lda OldT1+1
- sta VTIMR1+1
+ lda OldT2
+ sta VTIMR2
+ lda OldT2+1
+ sta VTIMR2+1
plp
.endif
; Turn mouse polling IRQ back on
lda POKMSK
- ora #%00000001 ; timer 1 enable
+ ora #%00000010 ; timer 2 enable
sta POKMSK
sta IRQEN
sta irq_enabled
sta irq_enabled
lda POKMSK
- and #%11111110 ; timer 1 disable
+ and #%11111101 ; timer 2 disable
sta IRQEN
sta POKMSK
;----------------------------------------------------------------------------
-; T1Han: Local IRQ routine to poll mouse
+; T2Han: Local IRQ routine to poll mouse
;
-T1Han: lda CRITIC ; if CRITIC flag is set, disable the
+T2Han: lda CRITIC ; if CRITIC flag is set, disable the
bne disable_me ; high frequency polling IRQ, in order
; not to interfere with SIO I/O (e.g.
- ; floppy access)
+ ; floppy access or serial I/O)
+
+ lda in_irq ; handler entered again?
+ bne skip ; yes, ignore this interrupt
+ inc in_irq
+ cli ; enable IRQs so that we don't block them for too long
tya
pha
tax
pla
tay
+ dec in_irq
+skip:
.ifdef __ATARIXL__
rts
.else
disable_me:
lda POKMSK
- and #%11111110 ; timer 1 disable
+ and #%11111101 ; timer 2 disable
sta IRQEN
sta POKMSK
lda #0
.export mouse_libref
.ifdef __ATARIXL__
- .import set_VTIMR1_handler
-mouse_libref := set_VTIMR1_handler
+ .import set_VTIMR2_handler
+mouse_libref := set_VTIMR2_handler
.else
.import _exit
mouse_libref := _exit
--- /dev/null
+;
+; Atari XL shadow RAM timer IRQ #2 handler
+;
+; Christian Groessler, chris@groessler.org, 2019
+;
+
+;DEBUG = 1
+
+.ifdef __ATARIXL__
+
+SHRAM_HANDLERS = 1
+ .include "atari.inc"
+ .include "romswitch.inc"
+ .export set_VTIMR2_handler
+
+
+.segment "LOWBSS"
+
+VTIMR2_handler: .res 3
+
+
+.segment "BSS"
+
+old_VTIMR2_handler:
+ .res 2
+
+
+.segment "LOWCODE"
+
+; timer interrupt handler:
+; disable ROM, call user handler, enable ROM again
+
+my_VTIMR2_handler:
+ disable_rom_quick
+ jsr VTIMR2_handler
+ enable_rom_quick
+ pla
+ rti
+
+.segment "CODE"
+
+; install or remove VTIMR2 handler
+; input: CF - 0/1 for remove/install handler
+; AX - pointer to handler (if CF=1)
+; registers destroyed
+
+set_VTIMR2_handler:
+
+ bcc @remove
+
+; install vector
+
+ stx VTIMR2_handler+2
+ sta VTIMR2_handler+1 ; save passed vector in low memory
+ lda #$4C ; "JMP" opcode
+ sta VTIMR2_handler
+
+ lda VTIMR2
+ sta old_VTIMR2_handler
+ lda VTIMR2+1
+ sta old_VTIMR2_handler+1
+
+ lda #<my_VTIMR2_handler
+ php
+ sei
+ sta VTIMR2
+ lda #>my_VTIMR2_handler
+ sta VTIMR2+1
+ plp
+ rts
+
+@remove: php
+ sei
+ lda old_VTIMR2_handler
+ sta VTIMR2
+ lda old_VTIMR2_handler+1
+ sta VTIMR2+1
+ plp
+ rts
+
+.endif ; .ifdef __ATARIXL__
;
; unsigned char getcpu (void);
;
- .include "zeropage.inc"
+ .include "zeropage.inc"
.export _getcpu
; ---------------------------------------------------------------------------
; jede jede@oric.org 2017-10-01
;
.export _cgetc
-
+
.import cursor
-
+
.include "telestrat.inc"
.proc _cgetc
- ; this routine could be quicker if we wrote in page 2 variables,
+ ; this routine could be quicker if we wrote in page 2 variables,
; but it's better to use telemon routine in that case, because telemon can manage 4 I/O
ldx cursor ; if cursor equal to 0, then switch off cursor
beq switchoff_cursor
-
+
ldx #$00 ; x is the first screen
BRK_TELEMON(XCSSCR) ; display cursor
jmp loop ; could be replaced by a bne/beq but 'jmp' is cleaner than a bne/beq which could expect some matters
-
-switchoff_cursor:
+
+switchoff_cursor:
; at this step X is equal to $00, X must be set, because it's the id of the screen (telestrat can handle 4 virtuals screen)
- BRK_TELEMON(XCOSCR) ; switch off cursor
-
-loop:
+ BRK_TELEMON(XCOSCR) ; switch off cursor
+
+loop:
BRK_TELEMON XRD0 ; waits until key is pressed
bcs loop
rts
-.endproc
+.endproc
; jede jede@oric.org 2017-01-22
.export _close
-
- .import addysp,popax
-
- .include "zeropage.inc"
+
+ .import addysp,popax
+
+ .include "zeropage.inc"
.include "telestrat.inc"
.include "errno.inc"
- .include "fcntl.inc"
-
+ .include "fcntl.inc"
+
; int open (const char* name, int flags, ...); /* May take a mode argument */
.proc _close
- BRK_TELEMON XCLOSE ; launch primitive ROM
+ BRK_TELEMON XCLOSE ; launch primitive ROM
rts
.endproc
;
; jede jede@oric.org 2017-02-25
-;
+;
.export _clrscr
-
+
.importzp sp
-
+
.include "telestrat.inc"
.proc _clrscr
; Switch to text mode
- BRK_TELEMON(XTEXT)
+ BRK_TELEMON(XTEXT)
lda #<SCREEN
ldy #>SCREEN
ldx #>(SCREEN+SCREEN_XSIZE*SCREEN_YSIZE)
lda #' '
BRK_TELEMON XFILLM
-
-
+
+
; reset prompt position
lda #<(SCREEN+40)
sta ADSCRL
lda #>(SCREEN+40)
sta ADSCRH
-
+
; reset display position
lda #$01
sta SCRY
lda #$00
- sta SCRX
+ sta SCRX
rts
-.endproc
+.endproc
; jede jede@oric.org 2017-02-25
;
.export _gotox
-
+
.import popa
-
+
.importzp sp
.include "telestrat.inc"
.proc _gotox
sta SCRX
rts
-.endproc
+.endproc
.proc _gotoy
sta SCRY
rts
-.endproc
+.endproc
ldx #0 ; Limit the length
L0: lda BUFEDT,x
- beq L3
- cmp #' '
- bne L1
- lda #0
- beq L3
+ beq L3
+ cmp #' '
+ bne L1
+ lda #0
+ beq L3
L1: sta name,x
inx
- cpx #FNAME_LEN
+ cpx #FNAME_LEN
bne L0
- lda #0
-L3:
- sta name,x
+ lda #0
+L3:
+ sta name,x
inc __argc ; argc always is equal to, at least, 1
-
+
ldy #1 * 2 ; Point to second argv slot
-
+
next: lda BUFEDT,x
beq done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next
+ beq next
found: cmp #'"' ; Is the argument quoted?
beq setterm ; Jump if so
txa ; Get low byte
clc
- adc #<BUFEDT
- bcc L4
- inc L5+1
+ adc #<BUFEDT
+ bcc L4
+ inc L5+1
L4:
sta argv,y ; argv[y]=&arg
-L5:
+L5:
lda #>BUFEDT
sta argv+1,y
iny
lda __argc ; Get low byte of argument count
cmp #MAXARGS ; Maximum number of arguments reached?
- bcc next ; Parse next one if not
-
-
+ bcc next ; Parse next one if not
+
+
done: lda #<argv
ldx #>argv
sta __argv
stx __argv + 1
rts
-
-
+
+
.segment "INIT"
term: .res 1
args: .res SCREEN_XSIZE * 2 - 1
param_found:
- .res 1
+ .res 1
; char* argv[MAXARGS+1]={name};
-argv:
- .addr name
+argv:
+ .addr name
.res MAXARGS * 2
.export _open
-
+
.import addysp,popax
-
+
.importzp sp,tmp2,tmp3,tmp1
-
-
+
+
.include "telestrat.inc"
.include "errno.inc"
- .include "fcntl.inc"
+ .include "fcntl.inc"
; int open (const char* name, int flags, ...); /* May take a mode argument */
.proc _open
dey ; ...checked (it generates a c compiler warning)
dey
dey
- beq parmok ; Branch if parameter count ok
- jsr addysp ; Fix stack, throw away unused parameters
+ beq parmok ; Branch if parameter count ok
+ jsr addysp ; Fix stack, throw away unused parameters
; Parameters ok. Pop the flags and save them into tmp3
jsr popax ; Get flagss
sta tmp3 ; save flags
; Get the filename from stack and parse it. Bail out if is not ok
- jsr popax ; Get name
- ldy tmp3 ; Get flags again
- BRK_TELEMON XOPEN ; launch primitive ROM
+ jsr popax ; Get name
+ ldy tmp3 ; Get flags again
+ BRK_TELEMON XOPEN ; launch primitive ROM
rts
.endproc
.include "zeropage.inc"
.include "telestrat.inc"
-
+
;int read (int fd, void* buf, unsigned count);
.proc _read
stx PTR_READ_DEST+1
sta ptr2 ; in order to calculate nb of bytes read
stx ptr2+1 ;
-
+
; jsr popax ; fp pointer don't care in this version
- lda ptr1 ;
+ lda ptr1 ;
ldy ptr1+1 ;
BRK_TELEMON XFREAD ; calls telemon30 routine
; compute nb of bytes read
lda PTR_READ_DEST+1
sec
sbc ptr2+1
- tax
+ tax
lda PTR_READ_DEST
sec
sbc ptr2
; Here A and X contains number of bytes read
rts
.endproc
-
-
; jede jede@oric.org 2017-02-25
;
.export _wherex
-
+
.importzp sp
.include "telestrat.inc"
ldx #$00
lda SCRX
rts
-.endproc
+.endproc
;
; jede jede@oric.org 2017-02-25
-;
+;
.export _wherey
-
+
.include "telestrat.inc"
.proc _wherey
ldx #$00
lda SCRY
rts
-.endproc
+.endproc
jsr popax ; get fd and discard
; if fd=0001 then it stdout
- cpx #0
- beq next
- jmp L1
-next:
- cmp #1
- beq L1
-
+ cpx #0
+ beq next
+ jmp L1
+next:
+ cmp #1
+ beq L1
+
; here it's a file opened
- lda ptr1
- sta PTR_READ_DEST
- lda ptr1+1
- sta PTR_READ_DEST+1
- lda ptr3
- ldy ptr3+1
+ lda ptr1
+ sta PTR_READ_DEST
+ lda ptr1+1
+ sta PTR_READ_DEST+1
+ lda ptr3
+ ldy ptr3+1
BRK_TELEMON XFWRITE
; compute nb of bytes written
-
+
lda PTR_READ_DEST+1
sec
sbc ptr1+1
- tax
+ tax
lda PTR_READ_DEST
sec
sbc ptr1
rts
-
-
+
+
L1: inc ptr2
bne L2
inc ptr2+1
BRK_TELEMON XWR0 ; macro send char to screen (channel 0 in telemon terms)
lda #$0D ; return to the beggining of the line
BRK_TELEMON XWR0 ; macro
-
+
ldx #$0D
-L3:
+L3:
BRK_TELEMON XWR0 ; macro
inc ptr1
rts
.endproc
-
-
bss_v = 0x88; // Testing BSS variable
for/*ever*/(;;) {
- // Vertical Sync signal
- TIA.vsync = 0x02;
- TIA.wsync = 0x00;
- TIA.wsync = 0x00;
- TIA.wsync = 0x00;
- TIA.vsync = 0x00;
-
- // Vertical Blank timer setting
- RIOT.tim64t = VBLANK_TIM64;
-
- // Doing frame computation during blank
- TIA.colubk = color++; // Update color
-
- // Wait for end of Vertical Blank
- while (RIOT.timint == 0) {}
- TIA.wsync = 0x00;
- TIA.vblank = 0x00; // Turn on beam
-
- // Display frame
- RIOT.t1024t = KERNAL_T1024;
- while (RIOT.timint == 0) {}
- TIA.wsync = 0x00;
- TIA.vblank = 0x02; // Turn off beam
-
- // Overscan
- RIOT.tim64t = OVERSCAN_TIM64;
- while (RIOT.timint == 0) {}
+ // Vertical Sync signal
+ TIA.vsync = 0x02;
+ TIA.wsync = 0x00;
+ TIA.wsync = 0x00;
+ TIA.wsync = 0x00;
+ TIA.vsync = 0x00;
+
+ // Vertical Blank timer setting
+ RIOT.tim64t = VBLANK_TIM64;
+
+ // Doing frame computation during blank
+ TIA.colubk = color++; // Update color
+
+ // Wait for end of Vertical Blank
+ while (RIOT.timint == 0) {}
+ TIA.wsync = 0x00;
+ TIA.vblank = 0x00; // Turn on beam
+
+ // Display frame
+ RIOT.t1024t = KERNAL_T1024;
+ while (RIOT.timint == 0) {}
+ TIA.wsync = 0x00;
+ TIA.vblank = 0x02; // Turn off beam
+
+ // Overscan
+ RIOT.tim64t = OVERSCAN_TIM64;
+ while (RIOT.timint == 0) {}
}
}
AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
AddCodeLine ("sta (sp),y");
AddCodeLine ("iny");
- AddCmpCodeIfSizeNot256 ("cpy #$%02X", Size);
+ AddCmpCodeIfSizeNot256 ("cpy #$%02X", Size);
AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
}
}
AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
AddCodeLine ("iny");
- AddCmpCodeIfSizeNot256 ("cpy #$%02X", Size);
+ AddCmpCodeIfSizeNot256 ("cpy #$%02X", Size);
AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
} else {
/* Use the easy way here: memcpy() */
FlagPragma (&B, &StaticLocals);
break;
- case PRAGMA_WRAPPED_CALL:
- WrappedCallPragma(&B);
- break;
+ case PRAGMA_WRAPPED_CALL:
+ WrappedCallPragma(&B);
+ break;
case PRAGMA_WARN:
WarnPragma (&B);
typedef struct IntPtrStack IntPtrStack;
struct IntPtrInner {
- long val;
- void *ptr;
+ long val;
+ void *ptr;
};
struct IntPtrStack {
unsigned Count;
#define BINFMT_DEFAULT 0 /* Default (binary) */
#define BINFMT_BINARY 1 /* Straight binary format */
#define BINFMT_O65 2 /* Andre Fachats o65 format */
+#define BINFMT_ATARIEXE 3 /* Standard Atari binary load */
<ClInclude Include="ld65\span.h" />
<ClInclude Include="ld65\spool.h" />
<ClInclude Include="ld65\tpool.h" />
+ <ClInclude Include="ld65\xex.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ld65\asserts.c" />
<ClCompile Include="ld65\span.c" />
<ClCompile Include="ld65\spool.c" />
<ClCompile Include="ld65\tpool.c" />
+ <ClCompile Include="ld65\xex.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
switch (Format) {
case BINFMT_BINARY:
+ case BINFMT_ATARIEXE:
Reloc = 0;
break;
#include "objdata.h"
#include "scanner.h"
#include "spool.h"
+#include "xex.h"
/* Descriptor holding information about the binary formats */
static BinDesc* BinFmtDesc = 0;
static O65Desc* O65FmtDesc = 0;
+static XexDesc* XexFmtDesc = 0;
{ "FORMAT", CFGTOK_FORMAT },
};
static const IdentTok Formats [] = {
+ { "ATARI", CFGTOK_ATARIEXE },
{ "O65", CFGTOK_O65 },
{ "BIN", CFGTOK_BIN },
{ "BINARY", CFGTOK_BIN },
F->Format = BINFMT_O65;
break;
+ case CFGTOK_ATARIEXE:
+ F->Format = BINFMT_ATARIEXE;
+ break;
+
default:
Error ("Unexpected format token");
}
+static void ParseXex (void)
+/* Parse the o65 format section */
+{
+ static const IdentTok Attributes [] = {
+ { "RUNAD", CFGTOK_RUNAD },
+ };
+
+ /* Remember the attributes read */
+ /* Bitmask to remember the attributes we got already */
+ enum {
+ atNone = 0x0000,
+ atRunAd = 0x0001,
+ };
+ unsigned AttrFlags = atNone;
+ Import *RunAd = 0;
+
+ /* Read the attributes */
+ while (CfgTok == CFGTOK_IDENT) {
+
+ /* Map the identifier to a token */
+ cfgtok_t AttrTok;
+ CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+ AttrTok = CfgTok;
+
+ /* An optional assignment follows */
+ CfgNextTok ();
+ CfgOptionalAssign ();
+
+ /* Check which attribute was given */
+ switch (AttrTok) {
+
+ case CFGTOK_RUNAD:
+ /* Cannot have this attribute twice */
+ FlagAttr (&AttrFlags, atRunAd, "RUNAD");
+ /* We expect an identifier */
+ CfgAssureIdent ();
+ /* Generate an import for the symbol */
+ RunAd = InsertImport (GenImport (GetStrBufId (&CfgSVal), ADDR_SIZE_ABS));
+ /* Remember the file position */
+ CollAppend (&RunAd->RefLines, GenLineInfo (&CfgErrorPos));
+ /* Eat the identifier token */
+ CfgNextTok ();
+ break;
+
+ default:
+ FAIL ("Unexpected attribute token");
+
+ }
+
+ /* Skip an optional comma */
+ CfgOptionalComma ();
+ }
+
+ /* Set the RUNAD import if we have one */
+ if ( RunAd )
+ XexSetRunAd (XexFmtDesc, RunAd);
+}
+
+
+
static void ParseFormats (void)
/* Parse a target format section */
{
{ "O65", CFGTOK_O65 },
{ "BIN", CFGTOK_BIN },
{ "BINARY", CFGTOK_BIN },
+ { "ATARI", CFGTOK_ATARIEXE },
};
while (CfgTok == CFGTOK_IDENT) {
ParseO65 ();
break;
+ case CFGTOK_ATARIEXE:
+ ParseXex ();
+ break;
+
case CFGTOK_BIN:
/* No attribibutes available */
break;
/* Create the descriptors for the binary formats */
BinFmtDesc = NewBinDesc ();
O65FmtDesc = NewO65Desc ();
+ XexFmtDesc = NewXexDesc ();
/* If we have a config name given, open the file, otherwise we will read
** from a buffer.
O65WriteTarget (O65FmtDesc, F);
break;
+ case BINFMT_ATARIEXE:
+ XexWriteTarget (XexFmtDesc, F);
+ break;
+
default:
Internal ("Invalid binary format: %u", F->Format);
CFGTOK_ID,
CFGTOK_VERSION,
CFGTOK_FORMAT,
+ CFGTOK_RUNAD,
CFGTOK_LOAD,
CFGTOK_RUN,
CFGTOK_ZP,
CFGTOK_OVERWRITE,
+ CFGTOK_ATARIEXE,
CFGTOK_O65,
CFGTOK_BIN,
--- /dev/null
+/*****************************************************************************/
+/* */
+/* xex.c */
+/* */
+/* Module to handle the Atari XEX binary format */
+/* */
+/* */
+/* */
+/* (C) 2018 Daniel Serpell */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* common */
+#include "alignment.h"
+#include "print.h"
+#include "xmalloc.h"
+
+/* ld65 */
+#include "xex.h"
+#include "config.h"
+#include "exports.h"
+#include "expr.h"
+#include "error.h"
+#include "global.h"
+#include "fileio.h"
+#include "lineinfo.h"
+#include "memarea.h"
+#include "segments.h"
+#include "spool.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+struct XexDesc {
+ unsigned Undef; /* Count of undefined externals */
+ FILE* F; /* Output file */
+ const char* Filename; /* Name of output file */
+ Import* RunAd; /* Run Address */
+ unsigned long HeadPos; /* Position in the file of current header */
+ unsigned long HeadEnd; /* End address of current header */
+ unsigned long HeadSize; /* Last header size, can be removed if zero */
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+XexDesc* NewXexDesc (void)
+/* Create a new XEX format descriptor */
+{
+ /* Allocate memory for a new XexDesc struct */
+ XexDesc* D = xmalloc (sizeof (XexDesc));
+
+ /* Initialize the fields */
+ D->Undef = 0;
+ D->F = 0;
+ D->Filename = 0;
+ D->RunAd = 0;
+ D->HeadPos = 0;
+ D->HeadEnd = 0;
+ D->HeadSize = 0;
+
+ /* Return the created struct */
+ return D;
+}
+
+
+
+void FreeXexDesc (XexDesc* D)
+/* Free a XEX format descriptor */
+{
+ xfree (D);
+}
+
+
+
+void XexSetRunAd (XexDesc* D, Import *RunAd)
+/* Set the RUNAD export */
+{
+ D->RunAd = RunAd;
+}
+
+
+
+static unsigned XexWriteExpr (ExprNode* E, int Signed, unsigned Size,
+ unsigned long Offs attribute ((unused)),
+ void* Data)
+/* Called from SegWrite for an expression. Evaluate the expression, check the
+** range and write the expression value to the file.
+*/
+{
+ /* There's a predefined function to handle constant expressions */
+ return SegWriteConstExpr (((XexDesc*)Data)->F, E, Signed, Size);
+}
+
+
+
+static void PrintNumVal (const char* Name, unsigned long V)
+/* Print a numerical value for debugging */
+{
+ Print (stdout, 2, " %s = 0x%lx\n", Name, V);
+}
+
+
+
+static void XexStartSegment (XexDesc *D, unsigned long Addr, unsigned long Size)
+{
+ /* Skip segment without size */
+ if (!Size)
+ return;
+
+ /* Store current position */
+ unsigned long Pos = ftell (D->F);
+ unsigned long End = Addr + Size - 1;
+
+ /* See if last header can be expanded into this one */
+ if (D->HeadPos && ((D->HeadEnd + 1) == Addr)) {
+ /* Expand current header */
+ D->HeadEnd = End;
+ D->HeadSize += Size;
+ fseek (D->F, D->HeadPos + 2, SEEK_SET);
+ Write16 (D->F, End);
+ /* Seek to old position */
+ fseek (D->F, Pos, SEEK_SET);
+ }
+ else
+ {
+ if (D->HeadSize == 0) {
+ /* Last header had no data, replace */
+ Pos = D->HeadPos;
+ fseek (D->F, Pos, SEEK_SET);
+ }
+
+ /* If we are at start of file, write XEX heder */
+ if (Pos == 0)
+ Write16 (D->F, 0xFFFF);
+
+ /* Writes a new segment header */
+ D->HeadPos = ftell (D->F);
+ D->HeadEnd = End;
+ D->HeadSize = Size;
+ Write16 (D->F, Addr);
+ Write16 (D->F, End);
+ }
+}
+
+
+
+static void XexFakeSegment (XexDesc *D, unsigned long Addr)
+{
+ /* See if last header can be expanded into this one, we are done */
+ if (D->HeadPos && ((D->HeadEnd + 1) == Addr))
+ return;
+
+ /* If we are at start of file, write XEX heder */
+ if (ftell (D->F) == 0)
+ Write16 (D->F, 0xFFFF);
+
+ /* Writes a new (invalid) segment header */
+ D->HeadPos = ftell (D->F);
+ D->HeadEnd = Addr - 1;
+ D->HeadSize = 0;
+ Write16 (D->F, Addr);
+ Write16 (D->F, D->HeadEnd);
+}
+
+
+
+static void XexWriteMem (XexDesc* D, MemoryArea* M)
+/* Write the segments of one memory area to a file */
+{
+ unsigned I;
+
+ /* Always write a segment header for each memory area */
+ D->HeadPos = 0;
+
+ /* Get the start address and size of this memory area */
+ unsigned long Addr = M->Start;
+
+ /* Walk over all segments in this memory area */
+ for (I = 0; I < CollCount (&M->SegList); ++I) {
+
+ int DoWrite;
+
+ /* Get the segment */
+ SegDesc* S = CollAtUnchecked (&M->SegList, I);
+
+ /* Keep the user happy */
+ Print (stdout, 1, " ATARI EXE Writing `%s'\n", GetString (S->Name));
+
+ /* Writes do only occur in the load area and not for BSS segments */
+ DoWrite = (S->Flags & SF_BSS) == 0 && /* No BSS segment */
+ S->Load == M && /* LOAD segment */
+ S->Seg->Dumped == 0; /* Not already written */
+
+ /* If this is the run memory area, we must apply run alignment. If
+ ** this is not the run memory area but the load memory area (which
+ ** means that both are different), we must apply load alignment.
+ ** Beware: DoWrite may be true even if this is the run memory area,
+ ** because it may be also the load memory area.
+ */
+ if (S->Run == M) {
+
+ /* Handle ALIGN and OFFSET/START */
+ if (S->Flags & SF_ALIGN) {
+ /* Align the address */
+ unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
+ if (DoWrite || (M->Flags & MF_FILL) != 0) {
+ XexStartSegment (D, Addr, NewAddr - Addr);
+ WriteMult (D->F, M->FillVal, NewAddr - Addr);
+ PrintNumVal ("SF_ALIGN", NewAddr - Addr);
+ }
+ Addr = NewAddr;
+ } else if (S->Flags & (SF_OFFSET | SF_START)) {
+ unsigned long NewAddr = S->Addr;
+ if (S->Flags & SF_OFFSET) {
+ /* It's an offset, not a fixed address, make an address */
+ NewAddr += M->Start;
+ }
+ if (DoWrite || (M->Flags & MF_FILL) != 0) {
+ /* "overwrite" segments are not supported */
+ if (S->Flags & SF_OVERWRITE) {
+ Error ("ATARI file format does not support overwrite for segment '%s'.",
+ GetString (S->Name));
+ } else {
+ XexStartSegment (D, Addr, NewAddr - Addr);
+ WriteMult (D->F, M->FillVal, NewAddr-Addr);
+ PrintNumVal ("SF_OFFSET", NewAddr - Addr);
+ }
+ }
+ Addr = NewAddr;
+ }
+
+ } else if (S->Load == M) {
+
+ /* Handle ALIGN_LOAD */
+ if (S->Flags & SF_ALIGN_LOAD) {
+ /* Align the address */
+ unsigned long NewAddr = AlignAddr (Addr, S->LoadAlignment);
+ if (DoWrite || (M->Flags & MF_FILL) != 0) {
+ XexStartSegment (D, Addr, NewAddr - Addr);
+ WriteMult (D->F, M->FillVal, NewAddr - Addr);
+ PrintNumVal ("SF_ALIGN_LOAD", NewAddr - Addr);
+ }
+ Addr = NewAddr;
+ }
+
+ }
+
+ /* Now write the segment to disk if it is not a BSS type segment and
+ ** if the memory area is the load area.
+ */
+ if (DoWrite) {
+ /* Start a segment with only one byte, will fix later */
+ XexFakeSegment (D, Addr);
+ unsigned long P = ftell (D->F);
+ SegWrite (D->Filename, D->F, S->Seg, XexWriteExpr, D);
+ unsigned long Size = ftell (D->F) - P;
+ /* Fix segment size */
+ XexStartSegment (D, Addr, Size);
+ PrintNumVal ("Wrote", Size);
+ } else if (M->Flags & MF_FILL) {
+ XexStartSegment (D, Addr, S->Seg->Size);
+ WriteMult (D->F, S->Seg->FillVal, S->Seg->Size);
+ PrintNumVal ("Filled", (unsigned long) S->Seg->Size);
+ }
+
+ /* If this was the load memory area, mark the segment as dumped */
+ if (S->Load == M) {
+ S->Seg->Dumped = 1;
+ }
+
+ /* Calculate the new address */
+ Addr += S->Seg->Size;
+ }
+
+ /* If a fill was requested, fill the remaining space */
+ if ((M->Flags & MF_FILL) != 0 && M->FillLevel < M->Size) {
+ unsigned long ToFill = M->Size - M->FillLevel;
+ Print (stdout, 2, " Filling 0x%lx bytes with 0x%02x\n",
+ ToFill, M->FillVal);
+ XexStartSegment (D, Addr, ToFill);
+ WriteMult (D->F, M->FillVal, ToFill);
+ M->FillLevel = M->Size;
+ }
+
+ /* If the last segment is empty, remove */
+ if (D->HeadSize == 0 && D->HeadPos) {
+ fseek (D->F, D->HeadPos, SEEK_SET);
+ }
+}
+
+
+
+static int XexUnresolved (unsigned Name attribute ((unused)), void* D)
+/* Called if an unresolved symbol is encountered */
+{
+ /* Unresolved symbols are an error in XEX format. Bump the counter
+ ** and return zero telling the caller that the symbol is indeed
+ ** unresolved.
+ */
+ ((XexDesc*) D)->Undef++;
+ return 0;
+}
+
+
+
+void XexWriteTarget (XexDesc* D, struct File* F)
+/* Write a XEX output file */
+{
+ unsigned I;
+
+ /* Place the filename in the control structure */
+ D->Filename = GetString (F->Name);
+
+ /* Check for unresolved symbols. The function XexUnresolved is called
+ ** if we get an unresolved symbol.
+ */
+ D->Undef = 0; /* Reset the counter */
+ CheckUnresolvedImports (XexUnresolved, D);
+ if (D->Undef > 0) {
+ /* We had unresolved symbols, cannot create output file */
+ Error ("%u unresolved external(s) found - cannot create output file", D->Undef);
+ }
+
+ /* Open the file */
+ D->F = fopen (D->Filename, "wb");
+ if (D->F == 0) {
+ Error ("Cannot open `%s': %s", D->Filename, strerror (errno));
+ }
+
+ /* Keep the user happy */
+ Print (stdout, 1, "Opened `%s'...\n", D->Filename);
+
+ /* Dump all memory areas */
+ for (I = 0; I < CollCount (&F->MemoryAreas); ++I) {
+ /* Get this entry */
+ MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I);
+ Print (stdout, 1, " ATARI EXE Dumping `%s'\n", GetString (M->Name));
+ XexWriteMem (D, M);
+ }
+
+ /* Write RUNAD at file end */
+ if (D->RunAd) {
+ Write16 (D->F, 0x2E0);
+ Write16 (D->F, 0x2E1);
+ Write16 (D->F, GetExportVal (D->RunAd->Exp));
+ }
+
+ /* Close the file */
+ if (fclose (D->F) != 0) {
+ Error ("Cannot write to `%s': %s", D->Filename, strerror (errno));
+ }
+
+ /* Reset the file and filename */
+ D->F = 0;
+ D->Filename = 0;
+}
--- /dev/null
+/*****************************************************************************/
+/* */
+/* xex.h */
+/* */
+/* Module to handle the Atari EXE binary format */
+/* */
+/* */
+/* */
+/* (C) 2018 Daniel Serpell */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef XEX_H
+#define XEX_H
+
+
+
+#include "config.h"
+#include "exports.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Structure describing the format */
+typedef struct XexDesc XexDesc;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+XexDesc* NewXexDesc (void);
+/* Create a new XEX format descriptor */
+
+void FreeXexDesc (XexDesc* D);
+/* Free a XEX format descriptor */
+
+void XexWriteTarget (XexDesc* D, File* F);
+/* Write a XEX output file */
+
+void XexSetRunAd (XexDesc* D, Import *RunAd);
+/* Set the RUNAD export */
+
+
+/* End of xex.h */
+
+#endif
BBRx, BBSx, RMBx, SMBx, WAI, and STP are unsupported
* BCD flag handling equals 6502 (unchecked if bug is simulated or wrong for
6502)
- * one cycle win for fetch-modify-write instructions ignored
- (e.g., ROL abs,x takes only 6 cycles if no page break occurs)
*/
#include "memory.h"
unsigned Val;
Cycles = 7;
Addr = MemReadWord (Regs.PC+1) + Regs.XR;
+ if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR))
+ --Cycles;
Val = MemReadByte (Addr) << 1;
MemWriteByte (Addr, (unsigned char) Val);
TEST_ZF (Val & 0xFF);
unsigned Val;
Cycles = 7;
Addr = MemReadWord (Regs.PC+1) + Regs.XR;
+ if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR))
+ --Cycles;
Val = MemReadByte (Addr);
ROL (Val);
MemWriteByte (Addr, Val);
unsigned char Val;
Cycles = 7;
Addr = MemReadWord (Regs.PC+1) + Regs.XR;
+ if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR))
+ --Cycles;
Val = MemReadByte (Addr);
SET_CF (Val & 0x01);
Val >>= 1;
unsigned Val;
Cycles = 7;
Addr = MemReadWord (Regs.PC+1) + Regs.XR;
+ if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR))
+ --Cycles;
Val = MemReadByte (Addr);
ROR (Val);
MemWriteByte (Addr, Val);
--- /dev/null
+; Sample using ATARI file format, by "atari-xex.cfg" linker configuration.
+;
+; This is a very simple example, shows a message to the screen, waits and
+; returns to DOS.
+;
+; Compile with:
+; cl65 -tatari -Catari-xex.cfg asm-xex.s -o prog.xex
+
+ .include "atari.inc"
+
+; Default RUNAD is "start", export that:
+ .export start
+
+
+; Write string to screen
+.proc puts
+ sta ICBAL
+ stx ICBAH
+ lda #PUTREC
+ sta ICCOM
+ ldx #$FF
+ stx ICBLL
+ inx
+ stx ICBLH
+ jsr CIOV
+ rts
+.endproc
+
+
+; Write a message and exit
+
+.proc start
+ lda #<msg
+ ldx #>msg
+ jsr puts
+
+
+ ; Delay before returning to DOS
+ lda #0
+ tax
+loop:
+ inx
+ cpx #$FF
+ adc #0
+ bcc loop
+
+ rts
+.endproc
+
+msg: .byte "Hello world", ATEOL
+
--- /dev/null
+FEATURES {
+ STARTADDRESS: default = $2E00;
+}
+MEMORY {
+ ZP: file = "", define = yes, start = $0082, size = $007E;
+ # First memory segment in file, load over COLOR registers:
+ COLOR: file = %O, start = $2C4, size = 5;
+ # Second memory segment, load at page 6:
+ PAGE6: file = %O, start = $600, size = 256;
+ # Third memory segment in file, load over SDLST register:
+ SDLST: file = %O, start = $230, size = 2;
+ # Main segment, load at "STARTADDRESS"
+ MAIN: file = %O, start = %S, size = $BC20 - %S;
+}
+FILES {
+ %O: format = atari;
+}
+FORMATS {
+ atari: runad = start;
+}
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp, optional = yes;
+ # Place segments in memory areas:
+ COLOR: load = COLOR, type = rw;
+ PAGE6: load = PAGE6, type = rw;
+ SDLST: load = SDLST, type = rw;
+ CODE: load = MAIN, type = rw;
+ RODATA: load = MAIN, type = ro optional = yes;
+ DATA: load = MAIN, type = rw optional = yes;
+ BSS: load = MAIN, type = bss, optional = yes, define = yes;
+}
--- /dev/null
+; Multiple segment ATARI file format sample, using custom linker script.
+;
+; This sample defines a custom display-list screen with no code, writing all
+; memory areas directly.
+;
+; See the linker script (multi-xex.cfg) for the definition of memory areas and
+; segments.
+;
+; Compile with:
+; cl65 -tatari -Cmulti-xex.cfg multi-xex.s -o prog.xex
+
+ .include "atari.inc"
+
+ .macpack atari
+
+; Default RUNAD is "start", export that:
+ .export start
+
+
+; We load color values directly into registers
+ .segment "COLOR"
+
+ .byte $16 ; COLOR0
+ .byte $46 ; COLOR1
+ .byte $00 ; COLOR2
+ .byte $6A ; COLOR3
+ .byte $82 ; COLOR4
+
+; We load our display list over page 6
+ .segment "PAGE6"
+
+display_list:
+ .byte DL_BLK8
+ .byte DL_BLK8
+ .byte DL_BLK8
+ .byte DL_BLK8
+ .byte DL_BLK8
+ .byte DL_BLK8
+ .byte DL_CHR20x8x2 | DL_LMS
+ .word screen_memory
+ .byte DL_CHR40x8x1
+ .byte DL_JVB
+ .word display_list
+
+screen_memory:
+ ; first text line: 20 bytes
+ scrcode " HeLlO wOrLd! "
+ ; second text line, 40 bytes
+ .byte 0, 0, 0, 0, 0, 0, 0, 0,70,71,70,71,70,71,70,71,70,71,70,71
+ .byte 70,71,70,71,70,71,70,71,70,71,70,71, 0, 0, 0, 0, 0, 0, 0, 0
+
+; We write directly to the display list pointer
+ .segment "SDLST"
+ .word display_list
+
+; And we load our main program
+ .code
+
+.proc start
+ ; Jump forever
+ jmp start
+.endproc
+
.bss
temp_x: .byte 0
temp_y: .byte 0
-temp_a: .byte 0
+temp_a: .byte 0
irq_count: .byte 0
nmi_count: .byte 0
psx: .byte 0
ldy temp_y
rts
.endproc
-
**
** Compile with "-DSTATIC_MOUSE" to statically link all available drivers.
** Compile with "-DMOUSE_DRIVER=<driver_sym>" to statically link the given driver.
-** E.g., -DMOUSE_DRIVER=atrsts_mou to just link with the Atari ST mouse driver.
+** E.g., -DMOUSE_DRIVER=atrst_mou to just link with the Atari ST mouse driver.
*/