diff --git a/README.md b/README.md index e3f1ab30f..891c31e86 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ the [cc65 web site](https://cc65.github.io): | Dr. Jozo Dujmović | Picocomputer (RP6502) | | Watara | Watura/QuickShot Supervision | | Synertek | SYM-1 | +| USSR | Agat-7/9 | A generic configuration to adapt cc65 to new targets is also around. diff --git a/asminc/agat.inc b/asminc/agat.inc new file mode 100644 index 000000000..b96d31834 --- /dev/null +++ b/asminc/agat.inc @@ -0,0 +1,39 @@ + +;----------------------------------------------------------------------------- +; Zero page stuff + +WNDLFT := $20 ; Text window left +WNDWDTH := $21 ; Text window width +WNDTOP := $22 ; Text window top +WNDBTM := $23 ; Text window bottom+1 +CH := $24 ; Cursor horizontal position +CV := $25 ; Cursor vertical position +BASL := $28 ; Text base address low +BASH := $29 ; Text base address high +CURSOR := $2D ; Cursor character +TATTR := $32 ; Text attributes +PROMPT := $33 ; Used by GETLN +VCOUT := $36 ; COUT Subroutine Vector +VCIN := $38 ; CIN Subroutine Vector +RNDL := $4E ; Random counter low +RNDH := $4F ; Random counter high +HIMEM := $73 ; Highest available memory address+1 + +;----------------------------------------------------------------------------- +; Vectors + +DOSWARM := $03D0 ; DOS warmstart vector +BRKVec := $03F0 ; Break vector +SOFTEV := $03F2 ; Vector for warm start +PWREDUP := $03F4 ; This must be = EOR #$A5 of SOFTEV+1 + +;----------------------------------------------------------------------------- +; Hardware + +; Keyboard input +KBD := $C000 ; Read keyboard +KBDSTRB := $C010 ; Clear keyboard strobe + +; Game controller +BUTN0 := $C061 ; Open-Apple Key +BUTN1 := $C062 ; Closed-Apple Key diff --git a/cfg/agat.cfg b/cfg/agat.cfg new file mode 100644 index 000000000..1a740cfc7 --- /dev/null +++ b/cfg/agat.cfg @@ -0,0 +1,44 @@ +# Default configuration + +FEATURES { + STARTADDRESS: default = $1903; +} +SYMBOLS { + __EXEHDR__: type = import; + __FILETYPE__: type = weak, value = $0006; # file type + __STACKSIZE__: type = weak, value = $0400; # 1k stack + __HIMEM__: type = weak, value = $C000; # Presumed RAM end +} +MEMORY { + ZP: file = "", define = yes, start = $0080, size = $001A; + HEADER: file = %O, start = %S - $003A, size = $003A; + MAIN: file = %O, define = yes, start = %S, size = __HIMEM__ - %S; + BSS: file = "", start = __ONCE_RUN__, size = __HIMEM__ - __STACKSIZE__ - __ONCE_RUN__; +} +SEGMENTS { + ZEROPAGE: load = ZP, type = zp; + EXEHDR: load = HEADER, type = ro, optional = yes; + STARTUP: load = MAIN, type = ro, optional = yes; + LOWCODE: load = MAIN, type = ro, optional = yes; + CODE: load = MAIN, type = ro; + RODATA: load = MAIN, type = ro; + DATA: load = MAIN, type = rw; + INIT: load = MAIN, type = rw, optional = yes; + ONCE: load = MAIN, type = ro, define = yes; + BSS: load = BSS, type = bss, define = yes; +} +FEATURES { + CONDES: type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__, + segment = ONCE; + CONDES: type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__, + segment = RODATA; + CONDES: type = interruptor, + label = __INTERRUPTOR_TABLE__, + count = __INTERRUPTOR_COUNT__, + segment = RODATA, + import = __CALLIRQ__; +} diff --git a/doc/agat.sgml b/doc/agat.sgml new file mode 100644 index 000000000..ca5338c5f --- /dev/null +++ b/doc/agat.sgml @@ -0,0 +1,79 @@ + + +
+Agat-7/9 - specific information for cc65 + +<author><url url="https://sourceforge.net/u/olegodintsov/profile/" name="Oleg A. Odintsov">,<newline> +<url url="mailto:sintechs@gmail.com" name="Konstantin Fedorov"> + +<abstract> +An overview over the Agat-7 and Agat-9 and theirs interfaces to the cc65 C +compiler. +</abstract> + +<!-- Table of contents --> +<toc> + +<!-- Begin the document --> + +<sect>Overview + +<p>The Agat was a series of 8-bit computers produced in the Soviet Union from 1983 to 1993. +It was based on Apple II architecture with all electronic components made in the Soviet Union except for 6502 microprocessors supplied by UMC (UM6502A). +<p>If compared to Apple II, Agat had many improvements such as color text mode, additional graphic modes and flexible memory controller. +Agat-7 had an Apple II compatibility card called "Module 121", while Agat-9 had a built-in Apple II+ mode activated by soft-switch. +<p>All mass-produced Agat models were disk-based systems, 2K ROM contained only basic machine language monitor and disassembler. +Agat-7 had 140K floppy-drive based on Apple DISK II, while Agat-9 was supplied with 840K drive having its own sector format and controller. + +<sect>Binary format<p> + +The standard binary file format generated by the linker for the Agat target is +an AppleSingle file to be compatible with AppleCommander <url url="https://applecommander.github.io/">. +The default load address is $1903. + + + +<sect>Platform-specific header files<p> + +Programs containing Agat-specific code may use the <tt/agat.h/ or +<tt/agat.inc/ include files. + +<sect>Usefull info<p> + +<sect1>Emulation<p> + +<enum> +<item> Oleg Odintsov's Agat Emulator - <url url="https://agatemulator.sourceforge.net/english.html"> +<item> MAME - <url url="https://www.mamedev.org/"> +</enum> + +<sect1>Links<p> +<enum> +<item> Most informative source on Agat (in russian) - <url url="https://agatcomp.ru"> +<item> Wikipedia - <url url="https://en.wikipedia.org/wiki/Agat_(computer)"> +<item> Controversial article on Agat from <url name="BYTE Magazine November 1984 Vol. 9, No. 12" url="https://archive.org/details/byte-magazine-1984-11/page/n135/mode/2up?view=theater">. +The author reviewed custom-build mockup Agat bearing little relation to even the early Agat systems. +</enum> + + +<sect>License<p> + +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: +<enum> +<item> 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. +<item> Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. +<item> This notice may not be removed or altered from any source + distribution. +</enum> + +</article> diff --git a/doc/index.sgml b/doc/index.sgml index 92df5e018..e39fd11b4 100644 --- a/doc/index.sgml +++ b/doc/index.sgml @@ -109,6 +109,9 @@ <descrip> + <tag><htmlurl url="agat.html" name="agat.html"></tag> + Topics specific to the Agat machines. + <tag><htmlurl url="apple2.html" name="apple2.html"></tag> Topics specific to the Apple ][. diff --git a/include/agat.h b/include/agat.h new file mode 100644 index 000000000..04ec16984 --- /dev/null +++ b/include/agat.h @@ -0,0 +1,76 @@ +#ifndef _AGAT_H +#define _AGAT_H + +/* Check for errors */ +#if !defined(__AGAT__) +# error This module may only be used when compiling for the Agat! +#endif + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Color defines */ +#define COLOR_BLACK 0x00 +#define COLOR_RED 0x01 +#define COLOR_GREEN 0x02 +#define COLOR_YELLOW 0x03 +#define COLOR_BLUE 0x04 +#define COLOR_MAGENTA 0x05 +#define COLOR_CYAN 0x06 +#define COLOR_WHITE 0x07 + +/* Characters codes */ +#define CH_CTRL_C 0x03 +#define CH_ENTER 0x0D +#define CH_ESC 0x1B +#define CH_CURS_LEFT 0x08 +#define CH_CURS_RIGHT 0x15 +#define CH_CURS_UP 0x19 +#define CH_CURS_DOWN 0x1A +#define CH_ESC 0x1B +#define CH_HLINE 0x1B +#define CH_VLINE 0x5C +#define CH_ULCORNER 0x10 +#define CH_URCORNER 0x12 +#define CH_LLCORNER 0x1D +#define CH_LRCORNER 0x1F + +/* Masks for joy_read */ +#define JOY_UP_MASK 0x10 +#define JOY_DOWN_MASK 0x20 +#define JOY_LEFT_MASK 0x04 +#define JOY_RIGHT_MASK 0x08 +#define JOY_BTN_1_MASK 0x40 +#define JOY_BTN_2_MASK 0x80 + +/* Return codes for get_ostype */ +#define AGAT_UNKNOWN 0x00 +#define AGAT_7 0x10 /* Agat 7 */ +#define AGAT_9 0x20 /* Agat 9 */ + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + +unsigned char get_ostype (void); +/* Get the machine type. Returns one of the AGAT_xxx codes. */ + +void rebootafterexit (void); +/* Reboot machine after program termination has completed. */ + +/* The following #defines will cause the matching functions calls in conio.h +** to be overlaid by macros with the same names, saving the function call +** overhead. +*/ +#define _bgcolor(color) COLOR_BLACK +#define _bordercolor(color) COLOR_BLACK + +/* End of agat.h */ + + +#endif diff --git a/include/target.h b/include/target.h index 7663a39dd..5f9d8859c 100644 --- a/include/target.h +++ b/include/target.h @@ -37,6 +37,8 @@ # include <apple2enh.h> #elif defined(__APPLE2__) # include <apple2.h> +#elif defined(__AGAT__) +# include <agat.h> #elif defined(__ATARI__) # include <atari.h> #elif defined(__ATARI2600__) diff --git a/libsrc/Makefile b/libsrc/Makefile index 8a4f11414..2f1b604d7 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -15,7 +15,8 @@ CBMS = c128 \ GEOS = geos-apple \ geos-cbm -TARGETS = apple2 \ +TARGETS = agat \ + apple2 \ apple2enh \ atari \ atarixl \ diff --git a/libsrc/agat/_scrsize.s b/libsrc/agat/_scrsize.s new file mode 100644 index 000000000..09d7e879f --- /dev/null +++ b/libsrc/agat/_scrsize.s @@ -0,0 +1,23 @@ +; +; Ullrich von Bassewitz, 26.10.2000 +; Konstantin Fedorov, 12.06.2025 +; +; Screen size variables +; + + .export screensize + + .include "agat.inc" + +screensize: + lda WNDWDTH + bit TATTR + bmi t64 + lsr +t64: + tax + lda WNDBTM + sec + sbc WNDTOP + tay + rts diff --git a/libsrc/agat/break.s b/libsrc/agat/break.s new file mode 100644 index 000000000..d46679ba2 --- /dev/null +++ b/libsrc/agat/break.s @@ -0,0 +1,113 @@ +; +; Ullrich von Bassewitz, 27.09.1998 +; Oleg A. Odintsov, Moscow, 2024 +; +; void __fastcall__ set_brk (unsigned Addr); +; void reset_brk (void); +; + + .export _set_brk, _reset_brk + .destructor _reset_brk + + ; Be sure to export the following variables absolute + .export _brk_a: abs, _brk_x: abs, _brk_y: abs + .export _brk_sr: abs, _brk_pc: abs + + .include "agat.inc" + +_brk_a = $45 +_brk_x = $46 +_brk_y = $47 +_brk_sr = $48 +_brk_sp = $49 +_brk_pc = $3A + +.bss +oldvec: .res 2 ; Old vector + + +.data +uservec: jmp $FFFF ; Patched at runtime + + +.code + +; Set the break vector +.proc _set_brk + + sta uservec+1 + stx uservec+2 ; Set the user vector + + lda oldvec + ora oldvec+1 ; Did we save the vector already? + bne L1 ; Jump if we installed the handler already + + lda BRKVec + sta oldvec + lda BRKVec+1 + sta oldvec+1 ; Save the old vector + +L1: lda #<brk_handler ; Set the break vector to our routine + ldx #>brk_handler + sta BRKVec + stx BRKVec+1 + rts + +.endproc + + +; Reset the break vector +.proc _reset_brk + + lda oldvec + ldx oldvec+1 + beq @L9 ; Jump if vector not installed + sta BRKVec + stx BRKVec+1 + lda #$00 + sta oldvec ; Clear the old vector + stx oldvec+1 +@L9: rts + +.endproc + + + +; Break handler, called if a break occurs + +.proc brk_handler + + sec + lda _brk_pc + sbc #$02 ; Point to start of brk + sta _brk_pc + lda _brk_pc+1 + sbc #$00 + sta _brk_pc+1 + + clc + lda _brk_sp + adc #$04 ; Adjust stack pointer + sta _brk_sp + + lda _brk_sr ; Clear brk + and #$EF + sta _brk_sr + + jsr uservec ; Call the user's routine + + lda _brk_pc+1 + pha + lda _brk_pc + pha + lda _brk_sr + pha + + ldx _brk_x + ldy _brk_y + lda _brk_a + + rti ; Jump back... + +.endproc + diff --git a/libsrc/agat/cclear.s b/libsrc/agat/cclear.s new file mode 100644 index 000000000..93a561ef4 --- /dev/null +++ b/libsrc/agat/cclear.s @@ -0,0 +1,18 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; void __fastcall__ cclear (unsigned char length); +; + + .export _cclear + .import COUT + .include "zeropage.inc" + +_cclear: + sta ptr1 + lda #$A0 +next: + jsr COUT + dec ptr1 + bne next + rts diff --git a/libsrc/agat/cgetc.s b/libsrc/agat/cgetc.s new file mode 100644 index 000000000..839e4314a --- /dev/null +++ b/libsrc/agat/cgetc.s @@ -0,0 +1,23 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; char cgetc (void); +; + + .export _cgetc + .import cursor + .include "agat.inc" + +_cgetc: + lda #$DF ; _ + bit cursor + bne hascur + lda #$00 +hascur: + sta CURSOR + jsr j1 + cmp #$A0 + bpl :+ + and #$7F +: rts +j1: jmp (VCIN) diff --git a/libsrc/agat/chline.s b/libsrc/agat/chline.s new file mode 100644 index 000000000..bc95b2a16 --- /dev/null +++ b/libsrc/agat/chline.s @@ -0,0 +1,33 @@ +; +; Ullrich von Bassewitz, 08.08.1998 +; Colin Leroy-Mira, 26.05.2025 +; Konstantin Fedorov, 12.06.2025 +; +; void chlinexy (unsigned char x, unsigned char y, unsigned char length); +; void chline (unsigned char length); +; + + .export _chlinexy, _chline, chlinedirect + .import gotoxy, putchar + + .include "zeropage.inc" + +_chlinexy: + pha ; Save the length + jsr gotoxy ; Call this one, will pop params + pla ; Restore the length and run into _chline + +_chline: + ldx #$1B ; horizontal line character + +chlinedirect: + stx tmp1 + cmp #$00 ; Is the length zero? + beq done ; Jump if done + sta tmp2 +: lda tmp1 ; Screen code + jsr putchar ; Direct output + dec tmp2 + bne :- +done: rts + diff --git a/libsrc/agat/clrscr.s b/libsrc/agat/clrscr.s new file mode 100644 index 000000000..8b2d7100b --- /dev/null +++ b/libsrc/agat/clrscr.s @@ -0,0 +1,10 @@ +; +; Kevin Ruland +; +; void clrscr (void); +; + + .export _clrscr + .import HOME + +_clrscr := HOME diff --git a/libsrc/agat/color.s b/libsrc/agat/color.s new file mode 100644 index 000000000..0992bb860 --- /dev/null +++ b/libsrc/agat/color.s @@ -0,0 +1,20 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char __fastcall__ textcolor (unsigned char color); +; + + + .export _textcolor + .include "agat.inc" + + +_textcolor: + ldx TATTR + eor TATTR + and #$07 + eor TATTR + sta TATTR + txa + and #$0F + rts diff --git a/libsrc/agat/cout.s b/libsrc/agat/cout.s new file mode 100644 index 000000000..ae9d8a177 --- /dev/null +++ b/libsrc/agat/cout.s @@ -0,0 +1,14 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; COUT routine +; + + .export COUT + .include "agat.inc" + +COUT: + cmp #$10 + bpl out + ora #$80 +out: jmp (VCOUT) diff --git a/libsrc/agat/cputc.s b/libsrc/agat/cputc.s new file mode 100644 index 000000000..b82ce22e6 --- /dev/null +++ b/libsrc/agat/cputc.s @@ -0,0 +1,60 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; Konstantin Fedorov, 12.06.2025 +; +; void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c); +; void __fastcall__ cputc (char c); +; + + .import COUT + .export _cputcxy, _cputc, newline, putchar,putchardirect + .import gotoxy, VTABZ + .include "agat.inc" + +_cputcxy: + pha + jsr gotoxy + pla +_cputc: + cmp #$0D ; Test for \r = carriage return + bne notleft + ldy #$00 + sty CH + rts +notleft: + cmp #$0A ; Test for \n = line feed + beq newline + +putchar: + ldy CH + sta (BASL),Y + iny + lda TATTR + bmi wch ; Skip if t64 + sta (BASL),Y + iny +wch: + sty CH + cpy WNDWDTH + bcc noend + ldy #$00 + sty CH +newline: + inc CV + lda CV + cmp WNDBTM + bcc :+ + lda WNDTOP + sta CV +: jmp VTABZ +noend: + rts + +putchardirect: + ldy CH + sta (BASL),Y + lda TATTR + bmi :+ + iny + sta (BASL),Y +: rts diff --git a/libsrc/agat/crt0.s b/libsrc/agat/crt0.s new file mode 100644 index 000000000..41f03b24d --- /dev/null +++ b/libsrc/agat/crt0.s @@ -0,0 +1,78 @@ +; +; Startup code for cc65 (Agat version) +; + + .export __STARTUP__ : absolute = 1 ; Mark as startup + .export _exit + + .import initlib, donelib + .import zerobss, callmain + .import __ONCE_LOAD__, __ONCE_SIZE__ ; Linker generated + + .include "zeropage.inc" + .include "agat.inc" + +; ------------------------------------------------------------------------ + + .segment "STARTUP" + jsr init + jsr zerobss + jsr callmain +_exit: + ldx #<exit + lda #>exit + jsr reset + jsr donelib +exit: + ldx #$02 +: lda rvsave,x + sta SOFTEV,x + dex + bpl :- + ldx #zpspace-1 +: lda zpsave,x + sta sp,x + dex + bpl :- + ldx #$FF + txs + jmp DOSWARM + + + + .segment "ONCE" + +init: + ldx #zpspace-1 +: lda sp,x + sta zpsave,x + dex + bpl :- + + ldx #$02 +: lda SOFTEV,x + sta rvsave,x + dex + bpl :- + + lda HIMEM + ldx HIMEM+1 + sta sp + stx sp+1 + ldx #<_exit + lda #>_exit + jsr reset + jmp initlib + + .code + +reset: + stx SOFTEV + sta SOFTEV+1 + eor #$A5 + sta PWREDUP + rts + + .segment "INIT" +zpsave: .res zpspace +rvsave: .res 3 diff --git a/libsrc/agat/cvline.s b/libsrc/agat/cvline.s new file mode 100644 index 000000000..63c0d4daf --- /dev/null +++ b/libsrc/agat/cvline.s @@ -0,0 +1,29 @@ +; +; Ullrich von Bassewitz, 08.08.1998 +; Colin Leroy-Mira, 26.05.2025 +; Konstantin Fedorov, 12.06.2025 +; +; void cvlinexy (unsigned char x, unsigned char y, unsigned char length); +; void cvline (unsigned char length); +; + + .export _cvlinexy, _cvline + .import gotoxy, putchardirect, newline + + .include "zeropage.inc" + +_cvlinexy: + pha ; Save the length + jsr gotoxy ; Call this one, will pop params + pla ; Restore the length and run into _cvline + +_cvline: + cmp #$00 ; Is the length zero? + beq done ; Jump if done + sta tmp2 +: lda #$5C ; vertical line character + jsr putchardirect ; Write, no cursor advance + jsr newline ; Advance cursor to next line + dec tmp2 + bne :- +done: rts diff --git a/libsrc/agat/exehdr.s b/libsrc/agat/exehdr.s new file mode 100644 index 000000000..3f3047bf9 --- /dev/null +++ b/libsrc/agat/exehdr.s @@ -0,0 +1,43 @@ +; +; Oliver Schmidt, 2012-06-10 +; +; This module supplies an AppleSingle version 2 file header + entry with +; ID 11 according to https://tools.ietf.org/rfc/rfc1740.txt Appendix A. +; +; Agat target uses this header only for compatibility with Apple Commander +; because Agat's 140K disk filesystem is identical to Apple II DOS 3.3 and +; "ac.jar -as" option can be used to import binaries into disk images. + + .export __EXEHDR__ : absolute = 1 ; Linker referenced + .import __FILETYPE__ ; Linker generated + .import __MAIN_START__, __MAIN_LAST__ ; Linker generated + +; ------------------------------------------------------------------------ + +; Data Fork +ID01_LENGTH = __MAIN_LAST__ - __MAIN_START__ +ID01_OFFSET = ID01 - START + +; ProDOS File Info +ID11_LENGTH = ID01 - ID11 +ID11_OFFSET = ID11 - START + +; ------------------------------------------------------------------------ + + .segment "EXEHDR" + +START: .byte $00, $05, $16, $00 ; Magic number + .byte $00, $02, $00, $00 ; Version number + .res 16 ; Filler + .byte 0, 2 ; Number of entries + .byte 0, 0, 0, 1 ; Entry ID 1 - Data Fork + .byte 0, 0, >ID01_OFFSET, <ID01_OFFSET ; Offset + .byte 0, 0, >ID01_LENGTH, <ID01_LENGTH ; Length + .byte 0, 0, 0, 11 ; Entry ID 11 - ProDOS File Info + .byte 0, 0, >ID11_OFFSET, <ID11_OFFSET ; Offset + .byte 0, 0, >ID11_LENGTH, <ID11_LENGTH ; Length +ID11: .byte 0, %11000011 ; Access - Destroy, Rename, Write, Read + .byte >__FILETYPE__, <__FILETYPE__ ; File Type + .byte 0, 0 ; Auxiliary Type high + .byte >__MAIN_START__, <__MAIN_START__ ; Auxiliary Type low +ID01: diff --git a/libsrc/agat/gotoxy.s b/libsrc/agat/gotoxy.s new file mode 100644 index 000000000..13e7cb747 --- /dev/null +++ b/libsrc/agat/gotoxy.s @@ -0,0 +1,28 @@ +; +; Ullrich von Bassewitz, 06.08.1998 +; Oleg A. Odintsov, Moscow, 2024 +; +; void __fastcall__ gotoxy (unsigned char x, unsigned char y); +; void __fastcall__ gotox (unsigned char x); +; + + .export gotoxy, _gotoxy, _gotox + .import popa, VTABZ + + .include "agat.inc" + +gotoxy: + jsr popa ; Get Y +_gotoxy: + clc + adc WNDTOP + sta CV ; Store Y + jsr VTABZ + jsr popa ; Get X +_gotox: + bit TATTR + bmi t64 + asl +t64: + sta CH ; Store X + rts diff --git a/libsrc/agat/gotoy.s b/libsrc/agat/gotoy.s new file mode 100644 index 000000000..ea0eadbf2 --- /dev/null +++ b/libsrc/agat/gotoy.s @@ -0,0 +1,16 @@ +; +; Ullrich von Bassewitz, 06.08.1998 +; Oleg A. Odintsov, Moscow, 2024 +; +; void __fastcall__ gotoy (unsigned char y); +; + + .import VTABZ + .export _gotoy + .include "agat.inc" + +_gotoy: + clc + adc WNDTOP + sta CV + jmp VTABZ diff --git a/libsrc/agat/home.s b/libsrc/agat/home.s new file mode 100644 index 000000000..a0434c9bb --- /dev/null +++ b/libsrc/agat/home.s @@ -0,0 +1,15 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; HOME routine +; + + .export HOME + .import COUT + + .include "agat.inc" + +HOME: + lda #$8C + jmp COUT + rts diff --git a/libsrc/agat/kbhit.s b/libsrc/agat/kbhit.s new file mode 100644 index 000000000..f2bc4fc9f --- /dev/null +++ b/libsrc/agat/kbhit.s @@ -0,0 +1,19 @@ +; +; Kevin Ruland +; Ullrich von Bassewitz, 2005-03-25 +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char kbhit (void); +; + + .export _kbhit + + .include "agat.inc" + +_kbhit: + lda KBD ; Reading KBD checks for keypress + rol ; if high bit is set, key was pressed + lda #$00 + tax + rol + rts diff --git a/libsrc/agat/randomize.s b/libsrc/agat/randomize.s new file mode 100644 index 000000000..9eef16f05 --- /dev/null +++ b/libsrc/agat/randomize.s @@ -0,0 +1,18 @@ +; +; Ullrich von Bassewitz, 07.11.2002 +; Oleg A. Odintsov, Moscow, 2024 +; +; void _randomize (void); +; /* Initialize the random number generator */ +; + + .export __randomize + .import _srand + + .include "agat.inc" + +__randomize: + ldx RNDH ; Use random value supplied by ROM + lda RNDL + jmp _srand ; Initialize generator + diff --git a/libsrc/agat/revers.s b/libsrc/agat/revers.s new file mode 100644 index 000000000..20c1b9bdb --- /dev/null +++ b/libsrc/agat/revers.s @@ -0,0 +1,38 @@ +; +; Ullrich von Bassewitz, 2005-03-28 +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char __fastcall__ revers (unsigned char onoff) +; unsigned char __fastcall__ flash (unsigned char onoff) +; + + .export _revers, _flash + + .include "agat.inc" + +_revers: + tax + beq noinv + lda TATTR + and #$D7 + sta TATTR + rts +noinv: + lda TATTR + ora #$20 + sta TATTR + rts + +_flash: + tax + beq noflash + lda TATTR + and #$DF + ora #$08 + sta TATTR + rts +noflash: + lda TATTR + ora #$20 + sta TATTR + rts diff --git a/libsrc/agat/vtabz.s b/libsrc/agat/vtabz.s new file mode 100644 index 000000000..88166eb35 --- /dev/null +++ b/libsrc/agat/vtabz.s @@ -0,0 +1,24 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; VTABZ routine +; + + .export VTABZ + .include "agat.inc" + +VTABZ: + lda CV + ror + ror + ror + and #$C0 + sta BASL + lda CV + lsr + lsr + eor BASH + and #$07 + eor BASH + sta BASH + rts diff --git a/libsrc/agat/wherex.s b/libsrc/agat/wherex.s new file mode 100644 index 000000000..a83f7cd75 --- /dev/null +++ b/libsrc/agat/wherex.s @@ -0,0 +1,19 @@ +; +; Kevin Ruland +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char wherex (void); +; + + .export _wherex + + .include "agat.inc" + +_wherex: + lda CH + bit TATTR + bmi t64 + lsr +t64: + ldx #$00 + rts diff --git a/libsrc/agat/wherey.s b/libsrc/agat/wherey.s new file mode 100644 index 000000000..4660a55f9 --- /dev/null +++ b/libsrc/agat/wherey.s @@ -0,0 +1,17 @@ +; +; Kevin Ruland +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char wherey (void); +; + + .export _wherey + + .include "agat.inc" + +_wherey: + lda CV + sec + sbc WNDTOP + ldx #$00 + rts diff --git a/libsrc/agat/write.s b/libsrc/agat/write.s new file mode 100644 index 000000000..6ac28f32c --- /dev/null +++ b/libsrc/agat/write.s @@ -0,0 +1,50 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; int __fastcall__ write (int fd, const void* buf, unsigned count); +; + + .export _write + .import popax, popptr1 + .import COUT + + .include "zeropage.inc" + +_write: + sta ptr2 + stx ptr2+1 + jsr popptr1 + jsr popax + + ; Check for zero count + ora ptr2 + beq done + + ; Get char from buf +next: ldy #$00 + lda (ptr1),y + + ; Replace '\n' with '\r' + cmp #$0A + bne output + lda #$8D + + ; Set hi bit and write to device +output: + jsr COUT ; Preserves X and Y + + ; Increment pointer + inc ptr1 + bne :+ + inc ptr1+1 + + ; Decrement count +: dec ptr2 + bne next + dec ptr2+1 + bpl next + + ; Return success +done: lda #$00 + rts + diff --git a/samples/Makefile b/samples/Makefile index 3680f542c..295b6883d 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -158,6 +158,11 @@ DIRLIST = tutorial geos atari2600 atari5200 apple2 gamate lynx supervision sym1 # -------------------------------------------------------------------------- # Lists of executables +EXELIST_agat = \ + ascii \ + checkversion \ + hello \ + sieve EXELIST_apple2 = \ ascii \ @@ -390,6 +395,7 @@ all: # -------------------------------------------------------------------------- # List of every supported platform TARGETS := \ + agat \ apple2 \ apple2enh \ atari \ diff --git a/samples/sieve.c b/samples/sieve.c index 7c3b9cd75..5ffc97b62 100644 --- a/samples/sieve.c +++ b/samples/sieve.c @@ -12,7 +12,7 @@ /* Workaround missing clock stuff */ -#ifdef __APPLE2__ +#if defined(__APPLE2__) || defined(__AGAT__) # define clock() 0 # define CLOCKS_PER_SEC 1 #endif diff --git a/src/ca65/main.c b/src/ca65/main.c index f3100162a..682e9be7f 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -350,6 +350,10 @@ static void SetSys (const char* Sys) NewSymbol ("__RP6502__", 1); break; + case TGT_AGAT: + NewSymbol ("__AGAT__", 1); + break; + default: AbEnd ("Invalid target name: '%s'", Sys); diff --git a/src/cc65/main.c b/src/cc65/main.c index a0c4848c9..53b106abd 100644 --- a/src/cc65/main.c +++ b/src/cc65/main.c @@ -307,6 +307,10 @@ static void SetSys (const char* Sys) DefineNumericMacro ("__RP6502__", 1); break; + case TGT_AGAT: + DefineNumericMacro ("__AGAT__", 1); + break; + default: AbEnd ("Unknown target system '%s'", Sys); } diff --git a/src/common/target.c b/src/common/target.c index 18da67b00..d1523f859 100644 --- a/src/common/target.c +++ b/src/common/target.c @@ -129,7 +129,25 @@ static const unsigned char CTPET[256] = { 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, }; - +/* Translation table KOI8-R -> Agat-9 */ +static unsigned char CTAgat[256] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0xA0, + 0x1B,0x5C,0x10,0x12,0x1D,0x1F,0x13,0x1C,0x11,0x1E,0x14,0xA0,0x02,0x5F,0xA0,0xA0, + 0xA0,0xA0,0xA0,0xA0,0xA0,0x9E,0x04,0xA0,0x3C,0x3E,0xA0,0xA0,0x30,0x32,0xA0,0x2F, + 0xA0,0xA0,0xA0,0x0F,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0, + 0xA0,0xA0,0xA0,0x9F,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, +}; /* One entry in the target map */ typedef struct TargetEntry TargetEntry; @@ -143,6 +161,7 @@ struct TargetEntry { ** CAUTION: must be alphabetically for bsearch(). */ static const TargetEntry TargetMap[] = { + { "agat", TGT_AGAT }, { "apple2", TGT_APPLE2 }, { "apple2enh", TGT_APPLE2ENH }, { "atari", TGT_ATARI }, @@ -224,6 +243,7 @@ static const TargetProperties PropertyTable[TGT_COUNT] = { { "sym1", CPU_6502, BINFMT_BINARY, CTNone }, { "kim1", CPU_6502, BINFMT_BINARY, CTNone }, { "rp6502", CPU_65C02, BINFMT_BINARY, CTNone }, + { "agat", CPU_6502, BINFMT_BINARY, CTAgat }, }; /* Target system */ diff --git a/src/common/target.h b/src/common/target.h index 730b8211e..d6c9fc35b 100644 --- a/src/common/target.h +++ b/src/common/target.h @@ -89,6 +89,7 @@ typedef enum { TGT_SYM1, TGT_KIM1, TGT_RP6502, + TGT_AGAT, TGT_COUNT /* Number of target systems */ } target_t;