Просмотр полной версии : Ретро-ЯП Millfork для Atari, Apple II, ZX Spectrum, MSX, CP/M, NES, Game Boy и MS-DOS
Oleg N. Cher
11.01.2024, 16:57
Ещё один язык, похожий на Cowgol. Поддерживает генерацию в z80 и 6502. Компилер написан на Scala. В поставке есть игра Pong для NES (прилагаемая в каком-то NES-туториале и переписанная с асма).
https://github.com/KarolS/millforkhttps://www.libhunt.com/compare-millfork-vs-cowgol
Кто целевая аудитория?
Millfork был разработан как язык для разработчиков старых 8-битных платформ, в основном для разработчиков игр, которые мало используют расширенные возможности C, но у которых нет времени писать ассемблер.
Что послужило вдохновением?
Главными вдохновителями были Atalan, а также Quetzalcoatl, Batari BASIC и NESHLA. К сожалению, Atalan был заброшен, а компилятор остался в нерабочем состоянии. Цель Millfork — добиться успеха там, где Atalanпотерпел неудачу.
Какие платформы поддерживаются?
Большие программы в Millfork были разработаны для Commodore 64.
Millfork также был протестирован (через эмуляторы) для запуска тривиальных программ на других 8-битных компьютерах Commodore, 8-битных компьютерах Atari, Apple II, BBC Micro, ZX Spectrum 48k, NEC PC-88, MSX, CP/M, NES, Game Boy, Atari Lynx, Atari 2600 и MS-DOS.
Поддержка других устройств, использующих поддерживаемые процессоры, может быть легко добавлена, обычно без изменения компилятора.
Какие микропроцессоры поддерживаются?
MOS 6502 и его потомки: 6510, 65C02, Ricoh 2A03 и в меньшей степени CSG 65CE02, Hudson Soft HuC6280 и WDC 65816. 6509 не поддерживается и не будет, однако с некоторой осторожностью к нему можно относиться как к обычному 6502.
Intel 8080, Intel 8085, Zilog Z80, Sharp LR35902 (также известный как GBZ80)
Существует также частичная экспериментальная поддержка Intel 8086 посредством автоматического преобразования 8080 в 8086. Сгенерированный код очень большой и очень медленный.
Поддержка Motorola 6809 появится в будущем. Вы можете проверить ход работы, создав собственную платформу с использованием процессора 6809, но подавляющее большинство программ Millfork даже не скомпилируются.
Почему Millfork, когда я могу использовать ассемблер?
Ассемблер не будет переносим. Если вы хотите использовать как 6502, так и Z80, вам придется поддерживать две отдельные кодовые базы.
Милфорк более продуктивен. Программисту не нужно беспокоиться о распределении регистров или размерах переменных.
Почему Millfork, когда я могу использовать C?
Миллфорк обычно немного быстрее.
Нет среды выполнения, поэтому проще создавать небольшие программы.
Многие функции, обычно встречающиеся в продвинутых ассемблерах, но редко встречающиеся в языках высокого уровня, также доступны в Millfork, например макросы, включение бинарных файлов, явное распределение памяти, инициализация массивов выражениями.
Millfork более тщательно обращается с кодировкой текста.
Большое разнообразие целочисленных типов почти произвольных размеров.
Семантика разработана для 8-битных микропроцессоров, поэтому обычно требуется менее явное приведение типов.
Низкоуровневые вещи, такие как перенос после арифметических операций или отдельных байтов более крупных переменных.
Встроенная поддержка десятичной арифметики.
Простое взаимодействие со ассемблером.
Звучит так, словно Миллфорк превосходит С во всех аспектах, верно?
К сожалению нет:
Милфорк очень требователен. Он позволяет избежать компиляции сложных выражений, особенно тех, которые содержат более крупные переменные.
Поддержка целочисленной математики не очень полная.
Математическая поддержка чисел с плавающей запятой отсутствует.
Арифметика указателей очень ограничена.
Препроцессор Millfork менее мощный, чем препроцессор C.
Нет поддержки связывания с внешними библиотеками, написанными не на Millfork. Вам нужно либо переписать внешнюю сборку в синтаксис сборки Millfork, либо сгенерировать статический двоичный файл и связать его вручную с помощью директивы file.
Поскольку работа над компилятором находится в стадии разработки, некоторые из упомянутых проблем могут быть улучшены в будущем.
У меня есть опыт работы с C и/или ассемблером. Что мне следует иметь в виду?
Посмотрите отличия от C (https://karols.github.io/millfork/various/cdiff.html) и отличия от ассемблера (https://karols.github.io/millfork/various/asmdiff.html).
Почему он называется Милфорк?
Это означает язык среднего уровня для компьютеров K ommodore .
(В Юте также есть шахтерский городок Милл-Форк, который, будучи подходящим компилятором для устаревших машин, в настоящее время заброшен.)
«Коммодор» не пишется через букву К!
Тсс.
Забавная штука
Пример на Atari(lines.mfk)
// idea @ilmenit
// https://demozoo.org/productions/280623
// for 8bit AtariXL, OS Rev 2
alias prev_x = os_OLDCOL.lo
alias cursor_x = os_COLCRS.lo
alias prev_y = os_OLDROW
alias cursor_y = os_ROWCRS
alias color = os_ATACHR
byte i
array(byte) colors = [
$00,$55,$AA,$FF
]
asm void openmode(byte register(a) m) @ $ef9c extern
asm void drawto() @ $f9c2 extern
void main(){
openmode(7)
// os_COLOR4 = 2
for i,0,to,159 {
os_ATACHR = colors[i&3]
cursor_x = i
prev_x = 159-i
prev_y = 0
cursor_y = 79
drawto()
}
while true {}
}
Компиляция(папка include в той же папке, где сам проект)
java -jar millfork.jar -I .\include\ -t A8 lines.mfk
Oleg N. Cher
30.08.2024, 00:31
Гм, дошло наконец-то, только долго, как до жирафа.
Маленькая бестолковая программа, написанная от нечего делать.
Dart Alver
31.08.2024, 18:22
Если б я чуть лучше по англицки понимал, а то переводчик чутка раздражает. ((
А так забавная вещица. Не знаю конечно насколько компактный код выдаёт данная весчь, но в принципе забавно.
Можно собственный вариант параметров машины подрисовать, только не понял, можно ли прописать форматы образов для вывода например как TRD (кажется нет). Хотя по сути это легко можно решить и внешними методами.
Тот-же sjasm в помощь. ))
Есть некое руководство по добавлению отдельного компьютера к компилятору, даже разработаны Mega65 и Aquarius.
Насчет ужасма - слышал, что допиливали формат под ассемблер, но не видел.
Забавная штука
Пример на Atari(lines.mfk)
А ты не разбирался, есть ли там поддержка работы со спрайтами и FS (чтение запись файлов)?
А ты не разбирался, есть ли там поддержка работы со спрайтами и FS (чтение запись файлов)?
не нашел примеров работы с файлами. Что касается PMG ака "спрайты", то можно попробовать написать код. Я раньше писал пример https://g0blinish.ucoz.ru/forblog_6502/corners.rar
можно попробовать написать код
Я так понял, что там можно что-то типа макросов как в ужасме наклепать? и при компиляции будет кусок асма вставляться?
Я так понял, что там можно что-то типа макросов как в ужасме наклепать? и при компиляции будет кусок асма вставляться?
Макросы можно использовать. При компиляции исходник создается, если использовать ключ командной строки -s
Макросы можно использовать.
Ну если не трудно, сделай плиз пример со спрайтом.
Наверное, спрайты и без макросов обойдутся(:
Попробую на днях заняться с 6502, сейчас занимаюсь Спектрумом. Есть неплохая статья (https://www.page6.org/archive/issue_08/page_10.htm)про PMG
- - - Добавлено - - -
Как-то так
// compile java -jar millfork.jar -I .\include\ -t A8 -s pmg.mfk
import stdlib
const byte pmgmem=$80 //pmgmem*256 == place for sprites
array(byte) sprd = [0,60,66,129,165,129,129,129,165,153,129,66,60,0]
void main ()
{
pointer pmg0
ubyte i
poke($D407,pmgmem)//PMGBASE place in memory
poke ($022F,%111110)//SDMCTL
poke ($D01D,3)//GRACTL Enable PM display
poke ($026F,1)//GPRIOR priority
poke ($D000,$30)//HPOSP0 horisontal place player 0
poke ($02C0,$CF)//PCOLR0 color of player 0
poke ($D008,0)//SIZEP0 size of player 0: ;0 = normal, 1 = double, 3 = quadruple
// copy sprite data to defined place
pmg0=word((pmgmem*256)+1024+30)
for i,0,to,13
{
pmg0[i]=sprd[i]
}
while true{}
}
Кстати, я написал не совсем верно, вместо poke можно использовать запись antic_pmbase=pmgmem. Но на код это не влияет.
Интересно посмотреть на генерацию кода копирования памяти
LDA #$1E
STA main$pmg0
LDA #$84
STA main$pmg0 + 1
LDA #0
STA main$i
.wh__00015:
LDY main$i
LDA sprd.array, Y
LDY main$i
STA (main$pmg0), Y
.fp__00017:
LDA main$i
CMP #$D
BNE .el__00019
Сделано все четко - адресация нулевой страницы и цикл 14 итераций подходит для 8-битного индексного регистра Y(он может принимать значения 0-255). Но со счетчиком цикла замудрили. Вообще-то я с подозрением отношусь к разным компиляторам, насмотрелся полученный индусский код, но у millfork'a сделано четко.
Конечно, можно написать лучше на ассемблере, но на то и сгенерированный исходник(:
На следующей неделе появится обновление версии, автор пока допиливает. Об изменениях сообщу.
Я раньше писал пример
А чего там субъект сквозь стены гуляет? Запускал на Altirra-2.40
proga.tap лучше простые окружности вывести имхо, а так непонятно, то ли задумка такая, то ли чё? Запускал на Fuse.
- - - Добавлено - - -
насмотрелся полученный индусский код
Главное, чтобы хотя бы работало. А шашечки за donate или "безд-возд-мездно БВМ, то есть даром (C) сова из мультика про Винни-Пуха Заходера" не обязательны.
А чего там субъект сквозь стены гуляет? Запускал на Altirra-2.40
Там внизу меняется 0/1 показывает коллизии.
Главное, чтобы хотя бы работало.
Ну да, новичкам очень сложно в ассемблер, а особенно в 6502. А так хоть какое-то облегчение. Ну и опять же какая-никакая кроссплатформенность.
proga.tap лучше простые окружности вывести имхо, а так непонятно, то ли задумка такая, то ли чё? Запускал на Fuse.
Тебя кастрюль покусал что ли?
Тебя кастрюль покусал что ли?
желателен простой пример с окружностью и/или Helloword.
- - - Добавлено - - -
А так хоть какое-то облегчение
сразу ковыряться в сложностях в нынешние времена 99% не захотят. А то, что сразу "взлетело и полетело" другое дело.
желателен простой пример с окружностью и/или Helloword.
пример Helloworld есть на Github
// compile with
// java -jar millfork.jar -I ${PATH}/include -t ${platform} ${PATH}/examples/hello_world/hello_world.mfk
import stdio
array hello_world = "Hello world"
void main() {
ensure_mixedcase()
#if CBM_64 || CBM_264
set_bg_color(white)
#endif
#if CBM_64 || CBM_264 || ZX_SPECTRUM
set_border(red)
#endif
putstr(hello_world, hello_world.length)
new_line()
putstrz("Hello world again"z)
#if not(CPM)
while(true){}
#endif
}
Окружность по Брезенхему написана, но есть один нюанс, пока выясняется
//Bresenham circle
//http://members.chello.at/easyfilter/bresenham.html
array(word) sa[192]
array(byte) bw = [$80,$40,$20,$10,8,4,2,1]
pointer sd
asm word call_22b0(byte a,byte c) @ $22b0 extern
void pp(ubyte x0,ubyte y0)
{
sd=sa[y0]+(x0>>3)
sd[0] |= bw[x0&7]
}
void inits()
{
ubyte i
for i,0,to,191
{
sa[word(i)]=call_22b0(i,0)
}
}
void cls()
{
asm
{
// xor a
// ld b,$18
// call 3652
ld hl,$4000
ld de,$4001
ld bc,6144
ld (hl),l
ldir
ld (hl),$38
ld bc,767
ldir
}
}
void circle(ubyte xm,ubyte ym,ubyte r)
{
sbyte x,y
unsigned16 err,rr
x=0-r// error with x=-r
y=0
err=2-r-r//2-2*r
do
{
pp(xm-x,ym+y)
pp(xm-y,ym-x)
pp(xm+x,ym-y)
pp(xm+y,ym+x)
rr=err
if (rr<=y) {
y=y+1
err=err+y+y+1//err+y*2+1
}
if (rr>x || err>y) {
x=x+1
err=err+x+x+1//err+x*2+1
}
} while (x<0)
}
void main() {
inits()//precalc screen lines adresses
cls()
circle(128,96,80)
while true {}
}
Совсем другое дело. Только что вот это за предупреждение?
WARN: (progas.mfk:21:17) Unsupported register parameter combination: (A,C)
sa[word(i)]=call_22b0(i,0)
^
INFO: Segment default: $8000-$81f9, size: 506 B (31820 B free, of which unused gaps 0 B)
в результате выполнения командника
millfork.jar -I .\include\ -t zxspectrum -s progas.mfk
"Главное, что хотя бы заработало"(с)
Это трюк для передачи параметров регистрам при вызове процедуры $22B0 - A=y координата, C=0.
Однако здравствуйте. Я понимаю, что яп ещё «в разработке», но то, что в макрос нельзя передать указатель на array, ну такоэ:
import stdio
array hello_world = "Hello ATARI!"
macro void print(array s) {
putstr(s, s.length)
}
void main() {
print(hello_world)
}
ERROR: Type `array` is not defined
Замечательно, судя по документации, в качестве аргумента может быть только 1 байт? o_O
macro void inc(byte b) {
b += 1
}
Ясно, чуть выше нашел:
cannot contain variable or array declarations
stdio (https://millfork.readthedocs.io/en/v0.3.30/stdlib/stdio/) не понимает претензий
stdio (https://millfork.readthedocs.io/en/v0.3.30/stdlib/stdio/) не понимает претензий
Я нашел откуда «ноги» названиям растут :) При желании можно наклепать свои вариации ;)
Там вообще ооочень интересная ситуация с синтаксисом (по крайней мере в функциях), прям питоном повяло, когда оно начало ругаться, что не может скомпилировать потому что отступы нарушены XD
Я тут набросал вариант с инклудом для спрайтов. но был немного неприятно удивлён, что вертикальное позиционирование спрайта это ещё тот гемор >_< я даж так и не понял как его менять нужно, на DLI что ли?
Так же (если я правильно понял) ширина спрайта всегда 16 пикселей (x2), максимум что можно ещё ещё зажЫрнить (x4 и x8).
Ну и зато теперь стало ясно как раскрашивают спрайтами картинки, когда оно на тексте ползает видно как его цвет меняется:
https://i.postimg.cc/pT6v2tvn/screenshot.png (https://postimages.org/)
Сырки:
import stdio
import sprites
array hello_world = "Hello ATARI!"
array(byte) sprite0 = [
%00000000,
%00111100,
%01000010,
%10000001,
%10100101,
%10000001,
%10000001,
%10000001,
%10100101,
%10011001,
%10000001,
%01000010,
%00111100,
%00000000
]
noinline asm void wait(byte register(a) f) {
clc
adc os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
bne .rt_check
rts
}
void main() {
putstr(hello_world, hello_world.length)
new_line()
putstrz("Hello world again"z)
sprCreate(sprite0, sprite0.length, $CF)
byte i
for i,48,to,200 {
sprPos(i, 0)
wait(1)
}
}
const byte pmgmem=$80 //pmgmem*256 == place for sprites
void sprCreate(pointer _sprData, byte _sprSize, byte _sprColor) {
pointer pmg0
ubyte i
poke($D407,pmgmem)//PMGBASE place in memory
poke ($022F,%111110)//SDMCTL
poke ($D01D,3)//GRACTL Enable PM display
poke ($026F,1)//GPRIOR priority
poke ($02C0,_sprColor)//$CF - PCOLR0 color of player 0
poke ($D008,0)//SIZEP0 size of player 0: ;0 = normal, 1 = double, 3 = quadruple
// copy sprite data to defined place
pmg0=word((pmgmem*256)+1024+30)
for i,0,to,_sprSize-1 {
pmg0[i]=_sprData[i]
}
}
void sprPos(byte x, byte y) {
poke ($D000,x)// $30 HPOSP0 horisontal place player 0
}
Shiny буду признателен, если подскажешь как правильно позиционировать по вертикали
81204
[ Shiny буду признателен, если подскажешь как правильно позиционировать по вертикали
Ты с приоритетом поиграл что ли?(:
Вертикальная позиция - адрес, куда ты записываешь данные
pmg0=word((pmgmem*256)+1024+30)
сменишь адрес на +31 и спрайт сместится вниз на 1 линию.
- - - Добавлено - - -
sprPos(i, 0)
wait(1)
лучше использовать wait() в начале, чтобы спрайт не мерцал.
Ты с приоритетом поиграл что ли?(:
Вроде нет.
Вертикальная позиция - адрес, куда ты записываешь данные
pmg0=word((pmgmem*256)+1024+30)
сменишь адрес на +31 и спрайт сместится вниз на 1 линию.
ооо! зер гÿт :) попробую.
лучше использовать wait() в начале, чтобы спрайт не мерцал.
Логично, бездумно дёрнул из чужого примера)
На обычных цветах
poke ($02C0,$CA)//PCOLR0 color of player 0
нет наложений.
На atariage много чего понаписано насчет сложения цветов. Удобнее отказаться от GR.0 - в нем два playfield сразу без фона.
И
while true {}
в конце void main(), а то Altirr-у корежит.
А как теперь рожицу стрелками двигать по экрану?
На обычных цветах
poke ($02C0,$CA)//PCOLR0 color of player 0
нет наложений.
На atariage много чего понаписано насчет сложения цветов. Удобнее отказаться от GR.0 - в нем два playfield сразу без фона.
ооо! это уже интереснее ;)
https://i.postimg.cc/3JBrfsMT/image.png (https://postimages.org/)
- - - Добавлено - - -
И
while true {}
в конце void main(), а то Altirr-у корежит.
А как теперь рожицу стрелками двигать по экрану?
Зачем? Оно после цикла в бейсик выходит. Если бейсика нет, вылетает в SelfTest.
Движений пока никаких нет. Это просто тест вывода спрайта.
Короче немного переделал вывод. Разбил на блок инициализации и блок отрисовки.
Добавил опрос джопстика и теперь рожу можно погонять по экрану.
sprites.mfk:
const byte pmgmem=$80 //pmgmem*256 == place for sprites
void sprInit() {
poke($D407,pmgmem)//PMGBASE place in memory
poke ($022F,%111110)//SDMCTL
poke ($D01D,3)//GRACTL Enable PM display
poke ($026F,1)//GPRIOR priority
poke ($D008,0)//SIZEP0 size of player 0: ;0 = normal, 1 = double, 3 = quadruple
}
void sprShow(pointer _sprData, byte _sprSize, byte _sprColor, byte x, byte y) {
pointer pmg0
ubyte i
poke ($02C0,_sprColor)//$CF - PCOLR0 color of player 0
//poke ($02C0,$CA)//PCOLR0 color of player 0
poke ($D000,x)// $30 HPOSP0 horisontal place player 0
// copy sprite data to defined place
pmg0=word((pmgmem*256)+1024+y)
for i,0,to,_sprSize-1 {
pmg0[i]=_sprData[i]
}
}
test.mfk:
import stdio
import sprites
array hello_world = "Hello ATARI!"
array(byte) sprite0 = [
%00000000,
%00111100,
%01000010,
%10000001,
%10100101,
%10000001,
%10000001,
%10000001,
%10100101,
%10011001,
%10000001,
%01000010,
%00111100,
%00000000
]
noinline asm void wait(byte register(a) f) {
clc
adc os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
bne .rt_check
rts
}
void main() {
byte pX
byte pY
byte joy
putstr(hello_world, hello_world.length)
new_line()
putstrz("Hello world again"z)
new_line()
sprInit()
// byte i
// for i,48,to,200 {
// wait(1)
// sprCreate(sprite0, sprite0.length, $CF, i, 30)
// }
pX = 60
pY = 30
putstrz("PosX: "z)
putword(pX)
putstrz(" PosY: "z)
putword(pY)
sprShow(sprite0, sprite0.length, %11000000, pX, pY)
while (true) {
wait(1)
joy = peek(632)
if (joy == 11 || joy == 10 || joy == 9) {
pX -= 1
} else if (joy == 7 || joy == 6 || joy == 5) {
pX += 1
}
if (joy == 14 || joy == 10 || joy == 6) {
pY -= 1
} else if (joy == 13 || joy == 9 || joy == 5) {
pY += 1
}
if (joy != 15) {
sprShow(sprite0, sprite0.length, %11000000, pX, pY)
}
}
}
Любопытный подход (: Опрос джойстика можно использовать с помощью теста битов.
Кстати, тут определяется игрок 0, а всего 0-3(не считая снарядов(missile) 0-3, которые можно объединить в спрайт.
Любопытный подход (: Опрос джойстика можно использовать с помощью теста битов.
Ну вообще да, это я с тетрадки проверку поднял, ещё когда в школе учился делал опрос на бейсике :D
Кстати, тут определяется игрок 0, а всего 0-3(не считая снарядов(missile) 0-3, которые можно объединить в спрайт.
Ну это да, есть задумка прикрутить спрайт из Boulder Dash и попробовать анимацию.
Кстати, посмотрел как «они» печатают символ, нашел кусок:
noinline asm void putchar(byte register(a) char) {
? tax
lda $347
pha
lda $346
pha
? txa
rts
}
inline void new_line() {
putchar($9b)
}
Что-то мне весь этот «конструкт» напоминает кубики лего ;)
Shiny подскажи плиз, как позиционируется курсор в текстовом режиме бейсика? Может есть какие-то адреса текущей позиции? Хочу выводить текущие координаты спрайта перетирая старые значения.
Shiny подскажи плиз, как позиционируется курсор в текстовом режиме бейсика? Может есть какие-то адреса текущей позиции? Хочу выводить текущие координаты спрайта перетирая старые значения.
Почитать Mapping The Atari (:
Сам не сталкивался с позиционированием, но в книге написано: 656 - строка, 657/658 - столбец.
https://forums.atariage.com/topic/288422-how-to-position-text-in-graphics-mode-116-in-atari-basic/#comment-4976073
В Altira 2.40 реакции на стрелки нет. Рожица добегает по строчке слева направо и всё! Нельзя ли другой тест под стрелки? В эмуляторе второй игрок - всегда компьютер.
В Altira 2.40 реакции на стрелки нет. Рожица добегает по строчке слева направо и всё! Нельзя ли другой тест под стрелки?
Опрос джойстика, а не клавишей со стрелками.
Почитать Mapping The Atari (:
Ну тут блин ещё искать где и как, а вдруг ты более подкован и уже делал такоэ ;)
Сам не сталкивался с позиционированием, но в книге написано: 656 - строка, 657/658 - столбец.
https://forums.atariage.com/topic/288422-how-to-position-text-in-graphics-mode-116-in-atari-basic/#comment-4976073
К сожалению не сработало, видимо дело или в бейсике или потому что у них граф.режим 2
- - - Добавлено - - -
В Altira 2.40 реакции на стрелки нет. Рожица добегает по строчке слева направо и всё! Нельзя ли другой тест под стрелки? В эмуляторе второй игрок - всегда компьютер.
Что-то это не то явно. Во первых код с движением закомментирован и никто никуда не должен ехать. А во вторых да, управление джойстиком. Стрелки это надо ещё с опросом клавиатуры разбираться.
- - - Добавлено - - -
Shiny Короче если попытаться включить GR.2 через $ef9c, как у тебя в lines сделано:
asm void openmode(byte register(a) m) @ $ef9c extern
То либо ничего, либо конфликт со спрайтами:
Если сначала вызвать openmode, а затем инитить спрайты, то оно «перетирается».
Если же сначала вызвать инит спрайтов, а затем openmode(2), то спрайт растягивает по вертикали в виде мусора и колбасит. При этом один фиг позиционирование не работает.
Видимо я не до конца понимаю как на асме переключаются режимы.
все время сначала включали режим, потом задавали спрайты.
Заодно надо посмотреть, где располагается Display List и адресована видеопамять - возможен конфликт.
- - - Добавлено - - -
К сожалению не сработало, видимо дело или в бейсике или потому что у них граф.режим 2
попробуй адреса 84, 85/86
- - - Добавлено - - -
import stdio
import stdlib
array hello_world = "Hello world"
void main() {
putstr(hello_world, hello_world.length)
poke(84,5)
poke(85,3)
putstr(hello_world, hello_world.length)
while(true){}
}
попробуй адреса 84, 85/86
Супер! Офигенно! То что надо!!!
p.s. с клавиатурой засада :) Если юзать как в примере с опросом через ROM:
lda #$C
sta $2A
lda $E425
pha
lda $E424
pha
rts
То да, код нажатой клавиши возвращается, но пока не отпустишь нифига нет.
Если выкинуть кусок в начале:
lda $E425 // GET ADRESS-VECTOR
pha // FROM ROM HANDLER TAB
lda $E424 // PLACE ADDRESS AS
pha // RETURN ADDRESS TO STACK
rts // JUMP TO ROM-ROUTINE
То да, оно работает. Но во первых каждый раз пибикает, во вторых медленно, а третьих если ни одна клавиша не нажата то из «цикла» не отпускает и всё тупо висит пока не нажмёшь клавишу.
Нужно искать какой-то опрос напрямую через порты, как на спектруме. Но ничего вменяемого пока не нашел.
peek(764). Если клавиша нажата, впиши в нее 255
В общем, какая-то байда с включением видеорежима - не получаю текстовый. Написал код по примеру, теперь не работает print #6. Заставил, чтобы заработало, нашлись доки(:
array(byte) hello_world = [$30,$31,$32,$33,$9B]
array(byte) nam=[$53,$3a,$9B]
void main() {
asm
{
lda #18
PHA ; Store on stack
LDX #$60 ; IOCB6 for screen
LDA #$C ; CLOSE command
STA $0342,X;ICCOM,X ; in command byte
JSR $E456;CIOV ; Do the CLOSE
LDX #$60 ; The screen again
LDA #3 ; OPEN command
STA $0342,X;ICCOM,X ; in command byte
LDA #nam&255 ; Name is "S:"
STA $0344,X;ICBAL,X ; Low byte
LDA #nam/256 ; High byte
STA $0345,X;ICBAH,X
PLA ; Get GRAPHICS n
STA $034B,X;ICAX2,X ; Graphics mode
AND #$F0 ; Get high 4 bits
EOR #$10 ; Flip high bit
ORA #$C ; Read or write
STA $034A,X;ICAX1,X ; n+16, n+32 etc.
JSR $E456;CIOV ; Setup GRAPHICS n
//print #6
lda #2
sta $84
lda #2
sta 85
ldx #$60
lda #hello_world&255
sta $0344,X ; ICBAL
lda #hello_world/256
sta $0345,X ; ICBAL
lda #9
sta $0342,X ; ICCOM
lda #0
sta $0348,X ;ICBLL
lda #$FF
sta $0349,X ;ICBLH
JSR $E456;CIOV
lda #0
sta 84
lda #2
sta 85
ldx #$60
lda #nam&255
sta $0344,X ; ICBAL
lda #nam/256
sta $0345,X ; ICBAL
lda #9
sta $0342,X ; ICCOM
lda #0
sta $0348,X ;ICBLL
lda #$FF
sta $0349,X ;ICBLH
JSR $E456;CIOV
}
// putstr(hello_world, hello_world.length)
poke(84,5)
poke(85,3)
// putstr(hello_world, hello_world.length)
while(true){}
}
Это было не просто, но мы справились. Структура спрайтов на атари это ещё то гениальное решение :mad:
Короче доделал универсальную шнягу для отображения спрайта, теперь задаёшь номер 0,1,2,3 и вгружаются данные для Player0 … Player3 соответственно.
Было немного неприятно узнать, что данные спрайта в начале и в конце надо обязательно обрамлять $00 иначе при движении вверх/вниз крайний байт начинает мазать в линию x_x
https://i.postimg.cc/htYTzkZg/bd.png (https://postimg.cc/0zpbhBqH)
Сырки:
sprites.mfk
const byte pmgmem=$80 //pmgmem*256 == place for sprites
void sprInit() {
poke($D407,pmgmem) // PMGBASE place in memory
poke ($022F,%00111110) // SDMCTL - Shadow of $D400 - Direct Memory Access (DMA) Control
// Bit Dec Function
// 7 128 not used
// 6 64 not used
// 5 32 Direct Memory Access on=1/off=0
// 4 16 One-line P/M-vertical resolution on=1/off=0
// 3 8 DMA for Players on=1/off=0
// 2 4 DMA for Missiles on=1/off=0
// 0,1 3 Wide playfield (48 bytes/chars)
// 0,1 2 Normal playfield (40 bytes/chars)
// 0,1 1 Narrow playfield (32 bytes/chars)
// 0,1 0 Playfield off
poke ($D01D,%00000011) // GRACTL controls PM and Triggers
// Bit Function
// 7 unused
// 6 unused
// 5 unused
// 4 unused
// 3 unused
// 2 Latch Triggers when =1
// 1 Turn on players when =1
// 0 Turn on missiles when =1
poke ($026F,1) // GPRIOR Priority Selection Register
// Bit Value Description
// 0 1 P0-P1-P2-P3 PF0-PF1-PF2-PF3 BAK
// 1 2 P0-P1 PF0-PF1-PF2-PF3 P2-P3 BAK
// 2 4 PF0-PF1-PF2-PF3 P0-P1-P2-P3 BAK
// 3 8 PF0-PF1 P0-P1-P2-P3 PF2-PF3 BAK
// 4 16 Four Missiles add up to be 5th player
// 5 32 Overlapping Players have 3rd color
// 6 64 GTIA Mode see next table
// 7 128 GTIA Mode see next table
poke ($D008,0) // [W] SIZEP0 size of player 0
// 0 = normal, 1 = double, 3 = quadruple
// [R] M0PL Collision Missile 0 with Player
poke ($D009,0) // [W] SIZEP1 size of player 1
poke ($D00a,0) // [W] SIZEP2 size of player 2
poke ($D00b,0) // [W] SIZEP3 size of player 3
// poke ($D00b,0) // [W] SIZEM size of missile
}
//asm void setColor(byte player, byte register(a) m) @ $02C0 + player extern
asm void setColor(byte player, byte register(a) m) {
LDX player
STA $02C0,X
RTS
}
asm void setPosX(byte player, byte register(a) m) {
LDX player
STA $D000,X
RTS
}
void sprShow(byte sprNum, pointer _sprData, byte _sprSize, byte _sprColor, byte x, byte y) {
pointer pmg0 //, pmg1
ubyte i
setColor(sprNum, _sprColor)
setPosX(sprNum, x)
// poke ($D004,x) // HPOSM0 horisontal place missile 0
// poke ($D005,x) // HPOSM1 horisontal place missile 1
// poke ($D006,x) // HPOSM2 horisontal place missile 2
// poke ($D007,x) // HPOSM3 horisontal place missile 3
// copy sprite data to defined place
pmg0=word((pmgmem*256) + 1024 + ($100 * sprNum) + y)
for i,0,to,_sprSize-1 {
pmg0[i]=_sprData[i]
}
}
boulder.mfk
import stdio
import sprites
array titleStr = "Boulder Dash ]["
array(byte) heroSpr0 = [0,$24,$3c,$5a,$5a,$3c,$18,$3c,$42,$18,0,$18,0]
array(byte) heroSpr1 = [0,$18,$24,$18,0,$18,0,0,$66,0]
array(byte) heroSpr2 = [0,$24,$24,$24,0]
byte color0 = $56
byte color1 = $0e
byte color2 = $c6
noinline asm void wait(byte register(a) f) {
clc
adc os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
bne .rt_check
rts
}
void printAt(byte x, byte y, byte i) {
poke(84, y)
poke(85, x)
putword(i)
putstrz(" "z)
}
void main() {
byte pX
byte pY
byte joy
sprInit()
putstr(titleStr , titleStr.length)
new_line()
putstrz("Use JoyStick, LOOK!"z)
new_line()
pX = 120
pY = 116
putstrz("PosX: "z)
putword(pX)
new_line()
putstrz("PosY: "z)
putword(pY)
new_line()
joy = peek(632)
putstrz("JoyStick: "z)
putword(joy)
sprShow(0, heroSpr0, heroSpr0.length, color0, pX, pY)
sprShow(1, heroSpr1, heroSpr1.length, color1, pX, pY+7)
sprShow(2, heroSpr2, heroSpr2.length, color2, pX, pY+11)
while (true) {
wait(1)
joy = peek(632)
if (joy == 11 || joy == 10 || joy == 9) {
pX -= 1
} else if (joy == 7 || joy == 6 || joy == 5) {
pX += 1
}
if (joy == 14 || joy == 10 || joy == 6) {
pY -= 1
} else if (joy == 13 || joy == 9 || joy == 5) {
pY += 1
}
if (joy != 15) {
sprShow(0, heroSpr0, heroSpr0.length, color0, pX, pY)
sprShow(1, heroSpr1, heroSpr1.length, color1, pX, pY+7)
sprShow(2, heroSpr2, heroSpr2.length, color2, pX, pY+11)
printAt(8, 2, pX)
printAt(8, 3, pY)
printAt(12, 4, joy)
} else {
printAt(12, 4, joy)
}
}
}
- - - Добавлено - - -
Что бы не рисовать ручками, решил тут поискать спрайты в памяти оригинального Boulder Dash.
Ага, щаз! Судя по структуре похоже оно тайлами фигарит :)
К слову нашёл сырки (https://github.com/TobyLobster/Boulderdash/blob/main/source/___1___.asm), кто-то декомпильнул оригинальный Boulder Dash
Интересно, а прокатит ли способ сложения цветов? В Preliminary Monty 16K это выглядит оч даже симпатично.
- - - Добавлено - - -
Добрался до Apple ii
Компиляция
java -jar millfork.jar -I .\include\ -t apple2 xp.mfk
java -jar AppleCommander-1.3.5.jar -d MASTER.dsk xp
java -jar AppleCommander-1.3.5.jar -p MASTER.dsk xp B 0xc00 < xp.a2
MASTER.dsk можно найти в дистрибутиве AppleWin,AppleCommander-1.3.5 найдете гуглом.
первая строка - компиляция
вторая строка - удаление с диска файла xp
третья строка - копирование файла на образ диска
Запуск: BRUN XP
Код xp.mfk
//Apple II lowres pattern
import stdlib
array(byte) cold=[$00,$88,$44,$CC,$EE,$AA,$FF,$55,$77,$66,$22,$33,$1 1,$BB,$99,$DD]
pointer linea @ 0x26//GBASL,GBASH
asm byte gbascalc(byte a) @ $F847 extern// in:A=Y coordinate, out:(GBASL,GBASH)=video memory address
asm byte setlores() @ $FB40 extern
void main() {
byte i,y
setlores()
poke ($C052,0)//enable graphics/text mixed mode
for y,0,to,23
{
gbascalc(y)//calculate address
for i,0,to,39
{
linea[i]=cold[(i&y)&15]
// linea[i]=cold[i&15]//obly debug output
}
}
while true{}
}
Ну шо, таки допилил Онимацию, теперь почти настоящий боудер получился :)
https://i.postimg.cc/TP6XsWys/1.gif (https://postimages.org/)
Как обычно сырки:
boulder.mfk:
import stdio
import sprites
array titleStr = "Boulder Dash ]["
array(byte) heroSpr0a = [0,$24,$3c,$5a,$5a,$3c,$18,$3c,$42,$18,0,$18,0]
array(byte) heroSpr0b = [0,$24,$3c,$7e,$5a,$3c,$18,$3c,$42,$18,0,$18,0]
array(byte) heroSpr0c = [0,$24,$3c,$7e,$7e,$3c,$18,$3c,$42,$18,0,$18,0]
array(byte) heroSpr1a = [0,$18,$42,$18,0,$18,0,0,$66,0]
array(byte) heroSpr1b = [0,$18,$24,$18,0,$18,0,0,$66,0]
array(byte) heroSpr1c = [0,$18,$24,$18,0,$18,0,$60,$06,0]
array(byte) heroSpr2a = [0,$24,$24,$24,0]
array(byte) heroSpr2b = [0,$24,$24,$04,0]
array(pointer) aFrames0 = [
heroSpr0a, heroSpr0b, heroSpr0c,
heroSpr0a, heroSpr0b, heroSpr0c,
heroSpr0a, heroSpr0b, heroSpr0c,
heroSpr0a, heroSpr0a, heroSpr0a, heroSpr0a,
heroSpr0a, heroSpr0a, heroSpr0a, heroSpr0a,
heroSpr0a, heroSpr0a, heroSpr0a, heroSpr0a
]
array(pointer) aFrames1 = [
heroSpr1a, heroSpr1a, heroSpr1a,
heroSpr1a, heroSpr1a, heroSpr1a,
heroSpr1a, heroSpr1a, heroSpr1a,
heroSpr1b, heroSpr1c, heroSpr1b, heroSpr1c,
heroSpr1b, heroSpr1c, heroSpr1b, heroSpr1c,
heroSpr1b, heroSpr1c, heroSpr1b, heroSpr1c
]
array(pointer) aFrames2 = [
heroSpr2a, heroSpr2a, heroSpr2a,
heroSpr2a, heroSpr2a, heroSpr2a,
heroSpr2a, heroSpr2a, heroSpr2a,
heroSpr2a, heroSpr2b, heroSpr2a, heroSpr2b,
heroSpr2a, heroSpr2b, heroSpr2a, heroSpr2b,
heroSpr2a, heroSpr2b, heroSpr2a, heroSpr2b
]
array(byte) aTime = [
150, 3, 3,
150, 3, 3,
150, 3, 3,
10, 10, 10, 10,
10, 10, 10, 10,
10, 10, 10, 10
]
byte color0 = $56
byte color1 = $0e
byte color2 = $c6
noinline asm void wait(byte register(a) f) {
clc
adc os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
bne .rt_check
rts
}
void printAt(byte x, byte y, byte i) {
poke(84, y)
poke(85, x)
putword(i)
putstrz(" "z)
}
void main() {
byte pX
byte pY
byte joy
byte posFrame
byte curTime
word curFrame0
word curFrame1
word curFrame2
sprInit()
putstr(titleStr , titleStr.length)
new_line()
putstrz("Use JoyStick, LOOK!"z)
new_line()
pX = 120
pY = 116
putstrz("PosX: "z)
putword(pX)
new_line()
putstrz("PosY: "z)
putword(pY)
new_line()
joy = peek(632)
putstrz("JoyStick: "z)
putword(joy)
posFrame = 0
curTime = aTime[posFrame]
curFrame0 = aFrames0[posFrame]
curFrame1 = aFrames1[posFrame]
curFrame2 = aFrames2[posFrame]
sprShow(0, curFrame0, heroSpr0a.length, color0, pX, pY)
sprShow(1, curFrame1, heroSpr1a.length, color1, pX, pY+7)
sprShow(2, curFrame2, heroSpr2a.length, color2, pX, pY+11)
while (true) {
wait(1)
joy = peek(632)
if (joy == 11 || joy == 10 || joy == 9) {
pX -= 1
} else if (joy == 7 || joy == 6 || joy == 5) {
pX += 1
}
if (joy == 14 || joy == 10 || joy == 6) {
pY -= 1
} else if (joy == 13 || joy == 9 || joy == 5) {
pY += 1
}
if (joy != 15) {
sprShow(0, curFrame0, heroSpr0a.length, color0, pX, pY)
sprShow(1, curFrame1, heroSpr1a.length, color1, pX, pY+7)
sprShow(2, curFrame2, heroSpr2a.length, color2, pX, pY+11)
printAt(8, 2, pX)
printAt(8, 3, pY)
printAt(12, 4, joy)
} else {
printAt(12, 4, joy)
}
curTime -= 1
if (curTime == 0) {
posFrame += 1
if (posFrame == aTime.length) {
posFrame = 0
}
curTime = aTime[posFrame]
curFrame0 = aFrames0[posFrame]
curFrame1 = aFrames1[posFrame]
curFrame2 = aFrames2[posFrame]
sprShow(0, curFrame0, heroSpr0a.length, color0, pX, pY)
sprShow(1, curFrame1, heroSpr1a.length, color1, pX, pY+7)
sprShow(2, curFrame2, heroSpr2a.length, color2, pX, pY+11)
}
}
}
блок спрайтов без изменений
Я конечно знатно прифигел, пока разбирался со спрайтами на атари и как ими рулить. Но я честно не подозревал какая ещё большая Ж с «ракетами». Это какой-то ппц:
Каждый спрайт имеет ширину 8 пикселей и всего 2 цвета (1 + прозрачный)
есть 4 «нормальных» спрайта шириной 8 пикселей... и 4 спрайта ракет шириной всего 2(!) пикселя...
но мы можем расположить их вместе, чтобы получить 5 спрайтов.
В смысле 2 пикселя? o_O Нахрена оно мне такое надо это недопаделие?
Я честно думал, что у меня будет 4 спрайта игроков и 4 спрайта противников (ракет) и сталкиваясь будет срабатывать коллизия.
А тут получается всего 4 спрайта и какие-то 4 каличных пульки.
Я в печали. Вообще тогда какой-либо смысл юзания спрайтов сваливается в 0. Смысл? Если даже сделать например 2 спрайта игрока и 2 спрайта противника, то как я понял коллизии между ними нет?
Shiny тебе слово.
А тут получается всего 4 спрайта и какие-то 4 каличных пульки.
Я в печали. Вообще тогда какой-либо смысл юзания спрайтов сваливается в 0. Смысл? Если даже сделать например 2 спрайта игрока и 2 спрайта противника, то как я понял коллизии между ними нет?
Shiny тебе слово.
Нормальные там пульки. Насчет столкновений не интересовался, но в Mapping есть описание по адресам $D000 и дальше.
- - - Добавлено - - -
Вот книга (https://www.atarimania.com/documents/Atari-Player-Missile-Graphics-in-BASIC.pdf) по pmg.
Вот книга (https://www.atarimania.com/documents/Atari-Player-Missile-Graphics-in-BASIC.pdf) по pmg.
О! ну хоть что-то стало понятнее. Спасибо буду копать.
Collisions
53248 - Missile 0 to playfield collision
53249 - Missile 1 to playfield collision
53250 - Missile 2 to playfield collision
53251 - Missile 3 to playfield collision
53256 - Missile 0 to player collision
53257 - Missile 1 to player collision
53258 - Missile 2 to player collision
53259 - Missile 3 to player collision
53260 - Player 0 to player collisions
53261 - Player 1 to player collisions
53262 - Player 2 to player collisions
53263 - Player 3 to player collisions
53252 - Player 0 to playfield
53253 - Player 1 to playfield
53254 - Player 2 to playfield
53255 - Player 3 to playfield
Осталось понять что есть «playfield»? Что-то типа тайлсета?
Грубо говоря в GR.3 точки, поставленные цветом 1,2,3 это и есть playfield
https://www.atariarchives.org/agagd/chapter1.php
Если долго мучаться, что-нибудь получится :)
В результате «мучений» родился AirWolf на минималках XD
https://i.postimg.cc/j27KPP3d/2.png (https://postimages.org/)
Player 0 и Player 1 это анимация вертолёта с лопостями ;)
Player2 - противник (в данном случае анимированный пульсирующий шарег)
Если они сталкиваются то +1 к смерти и вертолёт кидает на середину экрана (в оригинале конечно же должен быть тыдыщь)
Если нажать «огонь» на жопстике то вылетает 1 ракета (пока) и летил либо до края экрана, либо до противника.
При столкновении начисляются очки, а противника рандомит по оси Y.
ps. Сырки уже немного разрослись, поэтому не буду засирать форум, кому интересно архив в атачменте.
- - - Добавлено - - -
Грубо говоря в GR.3 точки, поставленные цветом 1,2,3 это и есть playfield
https://www.atariarchives.org/agagd/chapter1.php
Спасибо гляну, надо пейзаж уже рисовать ;)
Спасибо гляну, надо пейзаж уже рисовать ;)
Я просто нарисовал в Atari Tools для примера.
надо пейзаж уже рисовать
1)вертолет при движении вправо не разворачивается на экране. 2)Какая кнопка fire на клавиатуре в Altirra?
1)вертолет при движении вправо не разворачивается на экране. 2)Какая кнопка fire на клавиатуре в Altirra?
вангую, что Ctrl
- - - Добавлено - - -
Вообще это годный пример, но было б неплохо добавить несколько снарядов, как в SuperCobra
Ну даже без фона вполне себе миниGame. Только пару-тройку звуков добавить( при попадании во врага и при гибели вертолетика и звук вращающихся лопастей). Как там с поддержкой звуков в этом софте? Хорошо бы конечно и чтобы "рожа" периодически отпулькивалась. Ну и текст сделать размером поменьше никак нельзя?
1)вертолет при движении вправо не разворачивается на экране.
Ну в оригинале (AirWolf II) он и летит в одну сторону только ;)
2)Какая кнопка fire на клавиатуре в Altirra?
Вообще надо смотреть настройки, у меня выбран в качестве управления блок на цифровой клавиатуре 8,4,6,2 и 0 огонь
- - - Добавлено - - -
Вообще это годный пример, но было б неплохо добавить несколько снарядов, как в SuperCobra
Ну если вдохновения хватит, то можно прикрутить, и 2 ракеты и что бы враги отстреливались ;)
- - - Добавлено - - -
Ну даже без фона вполне себе миниGame. Только пару-тройку звуков добавить( при попадании во врага и при гибели вертолетика и звук вращающихся лопастей). Как там с поддержкой звуков в этом софте?
Так же как и со спрайтами :) Пишите свои процедуры и дрюкайте 4х канальный синтезатор
Хорошо бы конечно и чтобы "рожа" периодически отпулькивалась.
Сделаю ещё одного врага, стреляющего
Ну и текст сделать размером поменьше никак нельзя?
Текст стандартный шрифт 8x8.
Вообще надо смотреть настройки, у меня выбран в качестве управления блок на цифровой клавиатуре 8,4,6,2 и 0 огонь
0 при установках по умолчанию не работает, а Ctrl работает.
- - - Добавлено - - -
Ну в оригинале (AirWolf II) он и летит в одну сторону только
просто хвостом вперед летать как-то не айс
CodeMaster
08.09.2024, 12:00
просто хвостом вперед летать как-то не айс
Вертолёты так могут.
просто хвостом вперед летать как-то не айс
Блин :) Вы это сейчас серьёзно?
Не верю, что никогда не видели AirWolf 2 на спектруме o_O
https://www.youtube.com/watch?v=RNKUtmomF4I
- - - Добавлено - - -
Вертолёты так могут.
А в военное время число пи достигает четырёх! © :D
Вы это сейчас серьёзно?
здесь у противника цели прикреплены. А если цель летающая и может появится в 2d мире слева и справа, то и разворачивать вертолету хвост логично. Впрочем если Вашей целью было приблизится к прототипу - тогда да.
- - - Добавлено - - -
А в военное время число пи достигает четырёх!
это скорее у альпинистов "Мой дорогой сэр, абсолютно перпендикулярно-- 65°, нависающе -- 70°"
Поковырял я тут опрос клавиатуры для ATARI.
В принципе можно напрямую опрашивать кнопки напрямую из порта.
https://i.postimg.cc/g2g8GSvQ/xxx.png (https://postimages.org/)
Есть статусный порт 753, если значение там не 0, то значит что-то было нажато и последний код читаем из 53279.
Есть пару нюансов, опрашиваются в принципе все кнопки за исключением Start, Select, Option - они другим портом читаются (53279) причём биты ещё и инвертированы (0=если нажата)
Второй момент это повтор, как видно из скриншота, даже кратковременное нажатие дублит кнопку и тут уж надо думать как реализовать логику автоповтора.
Но как для теста пойдёт.
kbd.mfk:
import stdio
noinline asm void wait(byte register(a) f) {
clc
adc os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
bne .rt_check
rts
}
void printHex(byte val) {
byte c
c = (val >> 4)
if (c > 9) {
c = c - 10 + $41
} else {
c = c + $30
}
putchar(c)
c = (val & $0f)
if (c > 9) {
c = c - 10 + $41
} else {
c = c + $30
}
putchar(c)
}
void main() {
byte kbd, kbd2, kbd3, keyDel
putstrz("Key Test:"z)
new_line()
while (true) {
wait(1)
keyDel = peek(753)
if (keyDel != 0) {
kbd = peek(53769)
putword(kbd)
putstrz("($"z)
printHex(kbd)
putstrz(")"z)
new_line()
poke(53769, 0)
}
kbd2 = peek(53279)
if (kbd2 & %00000001 == 0) {
putstrz("Start"z)
new_line()
}
if (kbd2 & %00000010 == 0) {
putstrz("Select"z)
new_line()
}
if (kbd2 & %00000100 == 0) {
putstrz("Option"z)
new_line()
}
}
}
хм
import stdio
array hn="0123456789ABCDEF"
byte i
void main() {
for i,0,to,255
{
putchar(hn[i>>4])
putchar(hn[i&15])
putchar(32)
}
while(true){}
}
хм
Ну я взял асмовскую процедуру (http://forum.6502.org/viewtopic.php?f=2&t=3164#p36227) и попытался её натянуть на millfork XD
Поскольку в оригинале она как бы работала, но в купе с mf не очень, пришлось извещениями страдать. :)
; A = entry value
sed ;2 @2
tax ;2 @4
and #$0F ;2 @6
cmp #9+1 ;2 @8
adc #$30 ;2 @10
tay ;2 @12
txa ;2 @14
lsr ;2 @16
lsr ;2 @18
lsr ;2 @20
lsr ;2 @22
cmp #9+1 ;2 @24
adc #$30 ;2 @26
cld ;2 @28
; A = MSN ASCII char
; Y = LSN ASCII char
Вот не совсем понятно что делает «cmp #9+1»
выставляет флаг, а потом ADC его учитывает при сложении?
Вот не совсем понятно что делает «cmp #9+1»
выставляет флаг, а потом ADC его учитывает при сложении?
https://www.c64os.com/post/6502instructions
CMP Compare Accumulator
Compare sets processor flags as if a subtraction had been carried out.
If the accumulator and the compared value are equal, the result of the subtraction is zero and the Zero (Z) flag is set. If the accumulator is equal or greater than the compared value, the Carry (C) flag is set.
Неофициальное обновление
https://t.me/VintageSoftwareDevelopment/5/86844
к сожалению нет, но (по памяти)
- поправил генерацию asm (убрал лишнее, что не давала потом асм компилить в sjasm)
- поправил расчет переходов JR, было сломано
- поправил некоторые команды (редкие, неправильные опкоды были)
- из крупного, для asm макросов добавил форму типа DUP EDUP
asm macro aaa { ... }
+4 aaa()
развернет макрос 4 раза
Запасайтесь(:
Запасайтесь(:
нельзя ли перезалить куда-то или на торрент? А то "лиса и виноград"
нельзя ли перезалить куда-то или на торрент? А то "лиса и виноград"
Учетки для телеги нет? Заводи и не ленись.
https://disk.yandex.ru/d/UyR3KVFW-MMDPQ
Как только появится на github, удалю файл и оставлю ссылку.
Во многая сущности есть много печали...если это не банковские карты с деньгами ;)
- - - Добавлено - - -
Как только появится на github
да, это пока самая удобная файлоналивайка, имхо
Выдалось тут «немного» свободного времени и я основательно перелопатил свой прожект «AirWolf»:)
Ну во первых меня заколупало что каждый раз внесении изменений в очередной спрайт нужно опять извращаться с конверторами, пыжится анимацией, подбирать задержки кадров итд.
А поскольку я рисую спрайты в Aseprite, то было решено сделать скрипт который позволил бы выгружать сразу готовые данные спрайтов, анимаций, итд.
В результате чего появился вот такой небольшой прожект — «Aseprite-Scripts (https://github.com/LessNick/Aseprite-Scripts/)»
Там в readme всё подробно расписано что куда и зачем ( и как можно рисовать спрайты 4:1 и 8:1)
По поводу самого прожекта тоже завёл и выложил сырки — «AirWolf-Atari-Prototype (https://github.com/LessNick/AirWolf-Atari-Prototype)»
Из изменений структур:
— разнёс всё в отдельные файлы, оставив в main только относящееся к текущему проекту;
— отдельный файл «spritesData.mfk» с данными и анимациями, который собственно и выплёвывает Aseprite-Scripts;
— отдельный файл «sprites.mfk» в котором вынесено всё что связано с работой со спрайтами;
— отдельный файл «animation.mfk» всё что связано с анимацией;
— отдельный файл «control.mfk», туда вынес опрос джойстика и клавиатуры (курсоры + пробел)
Из нововведений:
— Добавилась смена анимаций, теперь когда вертолёт сталкивается с противником он типа взрывается;
— Добавилось, что при столкновении противника с ракетой он тоже анимировано уничтожается;
— Противники начали лететь на встречу (зелёный случайно появляется, а жёлтый шарег берёт Y у вертолёта)
— «Обломки» противника продолжают полёт и тоже повреждают;
— Сделал на тест полёт две ракеты. Одна медленная другая быстрее;
По поводу ракет не всё ясно, если 2 ракеты пересекаются, то дальше летит только 1. Не знаю баг это или фича :)
Далее уже можно думать про отрисовку playground.
класс!
у меня вылез один косяк, не смог повторить: налетел на зеленый корабль и погиб, мой вертолет появился на том же месте, и его добили обломки зеленого корабля.
класс!
Спасибо на добром слове.
у меня вылез один косяк, не смог повторить: налетел на зеленый корабль и погиб, мой вертолет появился на том же месте, и его добили обломки зеленого корабля.
Есть такой момент, сам в него попал. Нужно сделать временное бессмертие после «возрождения», типа там помигать вертолётом, он как бы есть, но ещё его нет :)
Кстати, не было идеи добавить звук?
Кстати, не было идеи добавить звук?
Очень даже была :) Надо однозначно добавить спец.эффектов
Кстати, о скролле:
https://atariprojects.org/2021/03/27/learn-to-implement-horizontal-scrolling-in-basic-on-atari-8-bit-computers-30-60-mins/
я использовал похожую идею в демо, но придумал способ до того, как увидел статью.
Короче меня тут сегодня прёт, и набросал по быстрому эдакий нойсер.
https://i.postimg.cc/SsvLv6Z0/noiser.png (https://postimages.org/)
Комбинации begin/end в купе со значениями distortion дают совершенно непредсказуемые результаты, так что подобрать что-то интересное можно только методом научного тыка.
Что делает бит Volume control вообще не ясно, звук просто затыкается :(
Короче скриншотьте у кого какие интересные значения получились :D
p.s. только благодаря Millfork удалось накидать так быстро ету самую хреновину ;)
Комбинации begin/end в купе со значениями distortion дают совершенно непредсказуемые результаты
на спеке много звуков делалось путём вывода в порт цепочки байтов из ПЗУ.
https://i.postimg.cc/1RBjcpW5/noiser2.png (https://postimages.org/)
Немного переделал плеер, что бы можно было вызывать на основном цикле, не в ущерб другой логике работы.
при значения 16,17,0 получился звук такой себе вертушки ;)
p.s. на github обновил AirWolf с новым SoundFX
CodeMaster
25.10.2024, 14:43
А есть онлайн-эмуляторы Атари?
А есть онлайн-эмуляторы Атари?
Есть jsMess, но он формат не понимает. Ибо нефиг.
А есть онлайн-эмуляторы Атари?
Я собирал MAME но там тоже не всё поддерживается. Скорее порт заброшен.
А есть онлайн-эмуляторы Атари?
а чем офф-лайн не устраивают?
а чем офф-лайн не устраивают?
Равнение на зумеров(:
CodeMaster
26.10.2024, 15:24
а чем офф-лайн не устраивают?
Лень ставить, что бы посмотреть одним глазом, что там получается.
Мне Altirra понравилась тем, что сразу скачиваешь и на 32 бит и на 64 и запускается все без проблем по умолчанию. При запуске щелкает - значит звук на месте. Меню щедрое. Загрузка в файлах сделана классно. Если самому разрабатывать то ИИ IDE с примерами вроде бы конечно нет. Ну вот Millfork и нашли. Тут правда как оказалось не про простоту и легкость вхождения, а про "переносимость". В которую применительно к 8-битникам мне вериться с трудом.
- - - Добавлено - - -
зумеров
это поколение юзеров "облачных решений" и ИИ основанном на МО?
Если самому разрабатывать то ИИ IDE с примерами вроде бы конечно нет. Ну вот Millfork и нашли. Тут правда как оказалось не про простоту и легкость вхождения, а про "переносимость". В которую применительно к 8-битникам мне вериться с трудом.
Чем плоха Mad Studio?
Насчет переносимости сильно сказано - железо у всех разное. Легкость вхождения тут не причем.
Пока вы тут спорите об эмуляторах, я потиху начал разбираться с графикой, и как это всё прикрутить к Millfork.
Прошерстив кучу текстов и поковыряв исходники ASM, что генерит Graph2Font, получил такую картину:
https://i.postimg.cc/7Ym6cS8L/1.png (https://postimages.org/)
Для начала определяем режим работы Antic, для примера обычный текстовый режим 2.
Создадим anticMap (DisplayList) в виде array(byte), в котором опишем режим отображения блока из 8 линий.
Там же зададим карту с тайлами array(byte) charMap, где какой символ будет расположен (0x00 - пустое место).
И останется лишь задать адрес расположения в памяти $D402, $D403
Надо отдать должное MillFork без проблем даёт работать с «указателями» на расположение массива в памяти и даже больше
внутри самого массива можно указать на расположение в памяти (вот такая рекурсия).
Для чего это нужно я не совсем пока понял, но примерах, что мне встречались, DisplayList для Antic заканчивается JPM на начало самого себя.
Так не менее интересный момент. Когда я захотел использовать свой шрифт, то выяснился нюанс. Поскольку память ATARI устроена таким образом,
что адрес расположения шрифта задаётся только страшим байтом адреса в $D409, то это внесло некоторые ограничения и шрифт должен располагаться кратно 0x0400.
Встала дилемма, у нас-то не ассемблер и ALIGN не сделать. Однако, как выяснилось Millfork писали умные люди и уже обо всём позаботились. Достаточно при
создании массива указать выравнивание и проблема решена ;)
array(byte) font align(0x0400) = [
Ну и поигравшись с разными значениями ANTIC можно получить не менее умилительные шрифты ;)
https://i.postimg.cc/g2jJPrmH/2.png (https://postimages.org/)
p.s. с прерываниями я пока не заморачивался, хотел разобраться для начала с базовой частью.
Здесь "выхлоп" не на "умильные шрифты" может быть направлен, а не на английские шрифты и всякие научные знаки типа производной, интеграла и прочего, имхо.
align(0x0400)
Не многовато? для шрифтов хватит выравнивание по 256 байт.
- - - Добавлено - - -
Здесь "выхлоп" не на "умильные шрифты" может быть направлен, а не на английские шрифты и всякие научные знаки типа производной, интеграла и прочего, имхо.
и лучше на уникодные эмодзи и всякую требуху.
align(0x0400)
Не многовато? для шрифтов хватит выравнивание по 256 байт.
Да вот видимо многовато :) Вообще брал из исходников graph2font:
.ALIGN $0400
fnt ins "logo2.fnt"
У них там вообще какой-то дико навороченный код с туевой хучей IFDEF.
К слову вопрос, что-то у меня не получается вектор прерываний указать. В дебаге не попадаю в эту область ни при каком раскладе.
Если я правильно понял, нужно сделать следующие шаги:
1) Запрещаем обработчик:
LDA #0
STA $D40E
2) Устанавливаем вектор на адрес с обработчиком:
LDA #lo(handler1)
STA $FFFA
LDA #hi(handler1)
STA $FFFB
3) Разрешаем обработчик:
LDA #$C0
STA $D40E
RTS
И нифига по адресу handler1 мы так и не попадаем ни разу. Причём в том же куске из graph2font это работает на ура. Может тут тоже какое «выравнивание по памяти необходимо» ?
Причём интересно, что в примерах из книжек они вектор выставляют по адресу $0200, $0201 кому верить?
- - - Добавлено - - -
Забавно, нашел в чём дело, сбил с толку комментарий:
;switch off ROM to get 16k more ram
lda #$fe
sta $D301
Это не просто отключает 16к, без этого вообще NMI не фунциклирен.
p.s. К слову выравнивание по $0400 в graph2font обусловлено тем, что они на лету шрифты чанки переключают для следующей области экрана
Просто .xex без извращений:
*=$2000
fnt .file "font.fnt"
start:
lda #font/256
sta 756
rts
*=$2E0
.word start
Что касается прерывания, то непонятно, что ты хочешь. Можно включить VBlank Interrupt(см. в моих исходниках 16К вызов jsr SETVBV). Если ты берешься за адреса $200-$201, то это Display List Interrupt. В этом случае нужно установить бит 7 для одной из строк - впиши вместо 2 $82 и на этой линии экрана произойдет прерывание. Но если ты поменяешь какие-то параметры экрана - шрифт и цвет, то параметры применятся ко всему экрану. Сам увидишь.
Просто .xex без извращений:
в смысле? это ж исходник с ассемблером, да? Как из него .xex получить?
тот же xasm https://github.com/pfusik/xasm
xasm ругается на это
fnt .file "font.fnt"
ERROR: Illegal instruction
тогда так
ORG $2000
fnt ins "HOHL.FNT"
start
lda #fnt/256
sta 756
ldy #0
setc tya
sta (88),y
iny
bne setc
jmp *
run start
Так работает. Русский шрифт есть? И как что-то выводить по-русски?
Что касается прерывания, то непонятно, что ты хочешь.
«Поциент путается в понятиях» ©
Короче я разобрался. Есть «Vertical Blank Interupt», который вызывается каждый кадр, в конце луча. И есть «Display List Interupt», который вызывается каждый раз, как будет встречен в листинге для antic'a.
Теперь чё я хочу, для начала менять шрифт и цвет. Для примера:
https://i.postimg.cc/nzfWgVDF/3.png (https://postimages.org/)
Вот три области, три раза дёргается DLI, и три раза меняются данные для антика (начало экрана).
Если первым всандалить вызов DLI, то в жопу уходит целая строка + всё ровно теряется 1 линия из следующего блока (DLI влетает с опозданием)
https://i.postimg.cc/Wb1HQHhk/4.png (https://postimages.org/)
Если сделать хитрый финт ушами и первый DLI засунуть в конец списка антика, то да, он сработает, но не повторится с начала (как ожидалось) а возьмёт данные шрифта и цветов по умолчанию (?)
https://i.postimg.cc/K8gJbSFR/5.png (https://postimages.org/)
Ну и третий коварный план скрестить ужа с ежом сразу и настройки для антика и вызов DLI превратив код в $C2.
Да такое сработало, 0я строка теперь не пропускается но DLI вызывается только на следующей.
Ну и опять же остаётся тонкая полоска в 1px отставания.
Нужен какой-то чёткий конструкт для антика. Хотя конечно, опять же возвращаясь к graph2font они там настройки антика не дёргают, только цвета и чанки меняют.
- - - Добавлено - - -
Так работает. Русский шрифт есть? И как что-то выводить по-русски?
Ну вообще-то 100 лет назад был сделан русификатор, переключается кнопкой инверсии, русские буквы вместо инвертированных символов, как впрочем и в других локализациях
https://i.postimg.cc/T3C3JwpD/1.png (https://postimages.org/)
https://i.postimg.cc/vmTHqsVS/2.png (https://postimages.org/)
Ну что сказать, почти получилось:
https://i.postimg.cc/28D7Mzx6/6.png (https://postimages.org/)
Пришлось пострадать некоторым извратом, а именно сделать вызов DLI на строку ранее, а потом 8(7) раз подождать луча, с помощью:
sta $D40A
И можно переключать шрифт и цвет. Всё как бы под линеечку, но вот что делать с самой первой линией не ясно, луч (DLI) явно поздновато прилетает.
Ну вообще-то 100 лет назад был сделан русификатор, переключается кнопкой инверсии, русские буквы вместо инвертированных символов, как впрочем и в других локализациях
Можете показать примерчик, где на одном экране русский и английский текст?
Ищи в разделе Atari, тут говорим о программировании на Millfork.
Ну что сказать, почти получилось:
Пришлось пострадать некоторым извратом, а именно сделать вызов DLI на строку ранее, а потом 8(7) раз подождать луча, с помощью:
ой ли? 1 линия.
- - - Добавлено - - -
Короче я разобрался. Есть «Vertical Blank Interupt», который вызывается каждый кадр, в конце луча
Вообще-то vbi происходит до и после кадра.
Вообще-то vbi происходит до и после кадра.
Ну тут мне карта и пошла, идеалити (ну почти)
https://i.postimg.cc/9fyHyt1Q/7.png (https://postimages.org/)
Если бы ещё от изврата с подгонкой линий разобраться, но в целом почти то, что я хотел.
Если бы ещё от изврата с подгонкой линий разобраться, но в целом почти то, что я хотел.
Снова неясно, что нужно. Может, VCOUNT поможет?
Кстати, есть неплохая книга DeReAtari, в ней раздел посвящен прерыванию.
- - - Добавлено - - -
И можно переключать шрифт и цвет. Всё как бы под линеечку, но вот что делать с самой первой линией не ясно, луч (DLI) явно поздновато прилетает.
Можно добавить к Display List $80 - выйдет черная полоса сверху. В Reloaded 16K так и используется.
Ищи в разделе Atari, тут говорим о программировании на Millfork.
можете показать примерчик на Millfork, где на одном экране русский и английский текст? :) просто как переводчик без этого сделать? Есть еще и по клавиатуре вопрос, но это действительно можно сходить поискать в интернете.
Снова неясно, что нужно.
Что бы было всё хорошо :)
Решил я посмотреть как выглядит на реале мой опус, и был приятно не впечатлён. Кажется понял почему в атари бейсике верх и низ срезаны, из-за диких глитчей развёртки в режиме антик 2 (текст)
https://i.postimg.cc/sX36PZJC/1.jpg (https://postimg.cc/3ybFYN6t)
Если же с начала и конца включить другой режим, например антик 4, то в середине прекрасно отображается и антик 2:
https://i.postimg.cc/RhDgzpxv/2.jpg (https://postimg.cc/T5nVV9Ps)
Есть подозрения, что и линия начала моя «плавает» из-за антика 2, попробую вгрузить для другого граф режима.
p.s. интересно, что в альтирре глитчей то нет :)
- - - Добавлено - - -
можете показать примерчик на Millfork, где на одном экране русский и английский текст?
Нет, хотя бы потому, что меня нет готовых шрифтов, технически не вижу никаких проблем, сделать хоть на арабском:
https://i.postimg.cc/ZYCXK2V8/image.png (https://postimages.org/)
Что бы было всё хорошо :)
Решил я посмотреть как выглядит на реале мой опус, и был приятно не впечатлён. Кажется понял почему в атари бейсике верх и низ срезаны, из-за диких глитчей развёртки в режиме антик 2 (текст)
а ты во всех векторах прерывания используешь запись в WSYNC?
- - - Добавлено - - -
можете показать примерчик на Millfork, где на одном экране русский и английский текст? :) просто как переводчик без этого сделать? Есть еще и по клавиатуре вопрос, но это действительно можно сходить поискать в интернете.
Я не могу. За сколько ты не брался проектов, столько и не довел до ума.
breeze, а такой код нормально отображается?
а ты во всех векторах прерывания используешь запись в WSYNC?
Я кучу экспериментов провёл и с ними и без, на начальной линии ему вообще пофиг на WSYNC
а такой код нормально отображается?
Да, на реале всё отлично, но тут у тебя как бейсике сверху и снизу чёрные блоки. А с полосками всё чётко.
У меня есть подозрение, что функцию для обработки прерывания генерит сам Millfork:
interrupt void dli() {
interrupt asm void vbi() {
А вот в готовом асме он там понапихивал кучу сохранеий, регистров итд, а так-ты то тикают, вот поэтому всё и съезжает скорее всего.
У меня есть подозрение, что функцию для обработки прерывания генерит сам Millfork:
interrupt void dli() {
interrupt asm void vbi() {
А вот в готовом асме он там понапихивал кучу сохранеий, регистров итд, а так-ты то тикают, вот поэтому всё и съезжает скорее всего.
Надо смотреть на код. Хотя, можно воткнуть на ассемблере.
- - - Добавлено - - -
Я кучу экспериментов провёл и с ними и без, на начальной линии ему вообще пофиг на WSYNC
Как раз глюк на вертикальной полосе и есть глюк с ДМА.
Надо смотреть на код. Хотя, можно воткнуть на ассемблере.
Короче я выкинул генерируемое и написал своё. В результате без всяких «прыжков в солнцу» линии стали ровные.
https://i.postimg.cc/GtJxDJXG/image.png (https://postimg.cc/GTtDwYwm)
interrupt asm void dli() {
pha
sta $D40A
lda intCount
cmp #00
bne .secondDLI
lda #hi(font2)
sta $D409
lda #12
sta $D01a
sta $D017
jmp .lastDLI
.secondDLI: lda #hi(font)
sta $D409
lda #15
sta $D01a
sta $D017
.lastDLI: inc intCount
lda intCount
cmp #02
bne .endDLI
lda #00
sta intCount
.endDLI: pla
rti
}
Как раз глюк на вертикальной полосе и есть глюк с ДМА.
Ну в других режимах антика этого не наблюдается, глитчи только в режиме 2 или 3
Нет, хотя бы потому, что меня нет готовых шрифтов
не надо рисовать шрифт, покажите пожалуйста код Millfork, который дает эту картинку с английским и арабским
- - - Добавлено - - -
За сколько ты не брался проектов, столько и не довел до ума
сейчас я уже полтора месяца работаю в фирме, у которой среди видов деятельности есть разработка ПО. Правда чтобы там удержаться надо личные продажи поднять с 0.4 млн. рублей в месяц до хотя бы 1.4 млн. рублей.
Разработка инструментального ПО это не моя стезя. Я когда работал программистом - то эмбедером или прикладным. Вы же тут поднимаете на пару c breeze инструментальное ПО. По интернету я надыбал, что Shiny как бы профи по Atari. А вот введение в программирование на ассемблере, на которое он ссылается совершенно нечитабельно из-за красного шрифта...во всяком случае для моих нездоровых глаз в очках.
не надо рисовать шрифт,
Шрифт так рисовать надо, поскольку тут несколько другой принцип построения. Скорее близкое, как были чанки на ZX.
покажите пожалуйста код Millfork, который дает эту картинку с английским и арабским
Картинку, что я привёл пример, рисует Atari DOS, со стоковым шрифтом из прошивки арабской версии атари 65хе.
Как закончу мытарства с DLI, конечно же всё выложу. Пока идут эксперименты смысла в этом не много.
breeze, а я все ждал, как ты сделаешь вектор dli для разных случаев.Иногда обходятся без доп. параметров, решается записью в адреса вектора $200,$201
- - - Добавлено - - -
Шрифт так рисовать надо, поскольку тут несколько другой принцип построения. Скорее близкое, как были чанки на ZX.
не влезут все символы - набор символов 128 плюс инверсные ограничен в запасе. У нас в школе был свой "русификатор", написанные местными умельцами, где строчные символы заменялись русскими буквами, и этого хватало. Только вот в gr.1 и gr.2 приходилось извращаться, чтобы писать по-русски.
- - - Добавлено - - -
Кстати,
lda intCount
cmp #00;<--------лишнее, не?
bne .secondDLI
- - - Добавлено - - -
https://i.ibb.co/w0dGdjD/atari000.png (https://imgbb.com/)
Тема русификации все же поднималась:
https://zx-pk.ru/threads/22985-atari-russian-charset/page4.html
- - - Добавлено - - -
А это собрано на коленках, на миллфорке
@breeze (https://zx-pk.ru/member.php?u=163), а я все ждал, как ты сделаешь вектор dli для разных случаев.
Да я уже тут 100500 вариантов перепробовал, если бы я сразу пнял разницу в VBI/DLI.И если бы «плеер» из graph2font ещё больше путаницы внёс, они там вообще один вектор для всех и потом проверяют, а кто прилетел VBI или DLI через:
bit nmist
bpl VBL
jmp DLI.dli_start
Иногда обходятся без доп. параметров, решается записью в адреса вектора $200,$201
Ну в принципе да, можно в конце каждого вызова DLI просто менять вектор на следующий
не влезут все символы - набор символов 128 плюс инверсные ограничен в запасе. У нас в школе был свой "русификатор", написанные местными умельцами, где строчные символы заменялись русскими буквами, и этого хватало. Только вот в gr.1 и gr.2 приходилось извращаться, чтобы писать по-русски.
Ну да, я уже чуть поковырял тот русификатор, что выше кидал. Там тоже сделаны вместо мелких латинских, большие русские.
Тут полноценное использование возможно только при собственной системе печати, например 80 символов в строке. Но на телике такой шрифт утухнешь читать.
https://i.postimg.cc/VsT8ww9P/sillypack2016.png (https://postimages.org/)
Кстати,
lda intCount
cmp #00;<--------лишнее, не?
bne .secondDLI
Кто знает ;)
в The Last Word используется ANTIC Mode F(Gr.8), этого хватает для символов.
Кстати, ты был прав насчет выравнивания шрифта:
http://user.xmission.com/~trevin/atari/antic_regs.html
в The Last Word используется ANTIC Mode F(Gr.8), этого хватает для символов.
Ну я так подозреваю, что принцип примерно такой же как на спектруме, делаем шрифт 4x6 с двойными символами, а потом копируем либо левую, либо правую половинку, в пустой шрифт, который отображается на экране?
Кстати, ты был прав насчет выравнивания шрифта:
http://user.xmission.com/~trevin/atari/antic_regs.html
Я забыл тогда отписать, поэкспериментировал с адресами, он не кратное плывёт шрифт сразу.
- - - Добавлено - - -
Тут другой вопрос возник. Только я разобрался с интами и выравниваниями новых шрифтов/цветов, словил леща при попытке переключить ширину экрана с 40 на 48 (для скроллов):
https://i.postimg.cc/dQHdMdWs/8.png (https://postimages.org/)
Чё только не делал, плывёт первая строчка и всё, не успевает переключится в 48й режим. А если сделать на строку выше, тогда уже включается 48й режим для предыдущей строки.
Ну я так подозреваю, что принцип примерно такой же как на спектруме, делаем шрифт 4x6 с двойными символами, а потом копируем либо левую, либо правую половинку, в пустой шрифт, который отображается на экране?
Вот шрифт от редактора
https://i.ibb.co/8072Cb5/2024-11-02-13-13-52.png (https://ibb.co/DtRkJYC)
Тут другой вопрос возник. Только я разобрался с интами и выравниваниями новых шрифтов/цветов, словил леща при попытке переключить ширину экрана с 40 на 48 (для скроллов):
Чё только не делал, плывёт первая строчка и всё, не успевает переключится в 48й режим. А если сделать на строку выше, тогда уже включается 48й режим для предыдущей строки.
я с этими режимами - 32/48 не сталкивался, надо смотреть исходник. А нужно ли оно для сдвигов?
Вот шрифт от редактора
Забавно, значит надо искать печаталку :)
я с этими режимами - 32/48 не сталкивался, надо смотреть исходник. А нужно ли оно для сдвигов?
Ну конечно, ты «печатаешь» за кадром новые тайлы, а потом они спокойно выезжают.
Очень подробная статья (https://www.playermissile.com/scrolling_tutorial/index.html) про эти самые скроллы.
Другой вопрос, что мне как обычно хочется «странного» :)
Я прошелся дебаггером в альтире (благо что там есть пошаговая возможность отображения луча экрана)
И пришел к выводу, что на одной линии DLI не успевает и сменить разрешайку на 48 и поменять шрифт и поменять цвета. Только 2 из 3х :)
И тут либо костылить и пропускать линию предыдущего блока, либо текущего, как вариант не трогать разрешайку и сразу всем врубить 48
Короче надо думать
А зачем тебе установка значений в DLI?
А зачем тебе установка значений в DLI?
Не понял вопроса :)
Есть три области, в них разные графические режимы, цвета и размеры.
По моему DLI как раз-таки и задумывался для переключения оных, или я чего-то не знаю?
Не понял вопроса :)
Есть три области, в них разные графические режимы, цвета и размеры.
По моему DLI как раз-таки и задумывался для переключения оных, или я чего-то не знаю?
Почему 3?
Я бы сделал две области - строка статуса со счетчиком игры и индикатором жизней и игровое поле с фоном - выходит джве, и параметры цвета и шрифта задаются для каждой зоны.
Тогда в Display List:
.byte $80 ; цвета и шрифт для статуса
.byte $42
.word status_text; это для данных
.byte $80 ; второе прерывание задает параметры для игрового поля
В прерывании удобнее сделать запись в $200/$201 адреса второго вектора, так меньше тактов.
Со сдвигом фона можно использовать трюк наподобие того, что я применял в 16К WYSIWIC
(https://www.pouet.net/prod.php?which=84100)
, но не буду отсылать к исходникам, а попробую описать:
Строки Display List:
.byte $52 ; $40+$10+2 lms+hscroll+mode_gr_0
.word screena
.byte $52
.word screena+80
.byte $52
.word screena+120
...
Данные фона генерируются и записываются столбцом по адресу screena+40,screena+120...
Когда сдвиг завершен(значения меняются от 3 до 0, да?), данные копируются с адреса screena+40 в screena, из screena+120 в screena+80.
Затем для строк увеличиваются адреса на 1: screena+1,screena+80+1.Если адрес первой строки достиг screena+40, то сброс на screena.
Выглядит сложно, но получишь бесконечный сдвиг фона.
Почему 3?
Ну сути это не меняет, можно хоть 10. В моём случае три потому что я хотел сделать вверху логотип, потом игровую область (нет смысла её делать огромной), и внизу очки, жизни итд.
В прерывании удобнее сделать запись в $200/$201 адреса второго вектора, так меньше тактов.
Ну скорее всего ты прав, попробую такой вариант.
Со сдвигом фона можно использовать трюк наподобие того, что я применял в 16К WYSIWIC (https://www.pouet.net/prod.php?which=84100)
До движений я так пока и не дошел. Но спасибо посмотрю.
Строки Display List:
.byte $52 ; $40+$10+2 lms+hscroll+mode_gr_0
Надо более детально врубится в команды дисплей листа, ибо я только пока понял, что:
$8x - вызвать DLI,
$4x - новый адрес для карты тайлов (экрана)
$Cx - совместить 8x и 4x (но оно тоже хер пойми как вызывается, толи адрес сначала меняется, толи сначала DLI влетает)
младшие значение режим антика $x2 $x4 итд
Сейчас вижу у тебя $10 как я понял это отсрочка или в конце строки DLI вызывать?
Что такое $52?
$8x - вызвать DLI,
$4x - новый адрес для карты тайлов (экрана)
$Cx - совместить 8x и 4x (но оно тоже хер пойми как вызывается, толи адрес сначала меняется, толи сначала DLI влетает)
младшие значение режим антика $x2 $x4 итд
Сейчас вижу у тебя $10 как я понял это отсрочка или в конце строки DLI вызывать?
Что такое $52?
Старшие биты 7-4 это и есть комбинация возможных значений. В mapping указаны значения, но вертикальный и горизонтальный сдвиги перепутаны.
$52 это комбинация флагов и режима: $40-команда LMS(нужно слово адреса в памяти), $10 - горизонтальный сдвиг, 2 - текстовый режим.
Прерывание начнется раньше, я указал $80.
Ну нашел наконец-таки нормальное описание битов:
7 6 5 4 3 2 1 0
DLI LMS VSCROLL HSCROLL
Mode
The 4 flags are:
DLI ($80): enable a display list interrupt when processing this instruction
LMS ($40): trigger a Load Memory Scan, changing where ANTIC looks for screen data, and requires an additional 2 byte address immediately following this instruction byte.
VSCROLL ($20): enable vertical scrolling for this mode line
HSCROLL ($10): enable horizontal scrolling for this mode line
- - - Добавлено - - -
Старшие биты 7-4 это и есть комбинация возможных значений. В mapping указаны значения, но вертикальный и горизонтальный сдвиги перепутаны.
$52 это комбинация флагов и режима: $40-команда LMS(нужно слово адреса в памяти), $10 - горизонтальный сдвиг, 2 - текстовый режим.
Прерывание начнется раньше, я указал $80.
Спасибо. Короче нужно ставить дебаг в альтирре и проходить потактово, что бы понять как это всё работает
Ну нашел наконец-таки нормальное описание битов:
полистай DeReAtari.pdf, итак расписано.
Спасибо. Короче нужно ставить дебаг в альтирре и проходить потактово, что бы понять как это всё работает
Шальная мысль: задать одно значение в ячейке 559(48 символов) и работать с памятью с учетом смещений. Но печать пойдет наискосок - если я правильно понял исходники OS, то процедура жестко пришита к стандартным видеорежимам, без учета размеров в 559:
https://atariwiki.org/wiki/Wiki.jsp?page=Atari%20800%20ROM%20OS%20Source%20Li sting
процедура INCRSB
- - - Добавлено - - -
https://i.ibb.co/mBT3cmv/2024-11-02-202035.jpg (https://ibb.co/b3mkKxH)
Обычный режим с poke 559,35 и poke 82,0
С помощью воззвания у чьей-то *** и врубления wide для всех сразу таки удалось получить что-то похожее на правду, вопрос теперь только в том, почему смещение у блока посредине не цикличное, а на пару байт всего?
Я на каждом вызове VBI инкременчу позицию
inc scrollPos
lda scrollPos
sta $D404 // HSCROLL
и получается вот это:
https://i.postimg.cc/wvt8p7Jt/1.gif (https://postimages.org/)
Lethargeek
03.11.2024, 02:47
С помощью воззвания у чьей-то *** и врубления wide для всех сразу таки удалось получить что-то похожее на правду, вопрос теперь только в том, почему смещение у блока посредине не цикличное, а на пару байт всего?
Я на каждом вызове VBI инкременчу позицию
так регистр четырёхбитный, так и должно быть
https://atariwiki.org/wiki/Wiki.jsp?page=HSCROL
так регистр четырёхбитный, так и должно быть
https://atariwiki.org/wiki/Wiki.jsp?page=HSCROL
Мда, атари как всегда не искали лёгких путей.
Смысл скоролла тогда теряется вообще напрочь. Нахрена мне 7 позиций только, если придётся «перезаливать» всю карту чанков. С таким же успехом я могу и просто её перезаливать.
Короче очередной бред какой-то.
возможно это поможет
https://www.playermissile.com/scrolling_tutorial/index.html
https://www.playermissile.com/_images/fine_scroll_2d_joystick.png
Да я уже этих статей кучу перешерстил. И эту тоже видел. Автор тоже хитрожёлтый, показывает пример примитивный что мол вот скроллится. Я честно даже не обратил внимания, что гифка не цикличная, думал просто обрезали. А вот панарамный скролл (который и надо было по сути показать) никто так и не сделал.
панарамный скролл (который и надо было по сути показать) никто так и не сделал.
https://youtu.be/msRuWEvaB8w?si=ZhftvtSYMksNiFr_
https://youtu.be/XKWyteiZKmc?si=WhZ0T0LgH4QAIdb6
breeze, держись! Спектрумята идут на помощь(:
Lethargeek
03.11.2024, 15:30
Смысл скоролла тогда теряется вообще напрочь. Нахрена мне 7 позиций только, если придётся «перезаливать» всю карту чанков. С таким же успехом я могу и просто её перезаливать.
может, и не всю; вероятно, можно изменять начальный адрес сканлайна и только по краю подрисовать
- - - Добавлено - - -
хотя мб и адреса лишь определённой кратности только можно
Мда, атари как всегда не искали лёгких путей.
Смысл скоролла тогда теряется вообще напрочь. Нахрена мне 7 позиций только, если придётся «перезаливать» всю карту чанков. С таким же успехом я могу и просто её перезаливать.
Короче очередной бред какой-то.
Не надо ничего перезаливать. Надо увеличить адреса в Display List на 1.
Примерно так. только меня на асм хватило.
Решил пока отвлечься от скроллов и заняться не менее интересной штукой, как чтение файлов с диска.
Чисто теоретически опять «ничего сложного», но блин! как же геморно искать по крупицам информацию, её вроде как и вагон в каждой книжке, но где-то одно не дописано, где-то воды много итд.
Досов на атари как известно много, все они разные и в меру навороченные. Остановится решил на XDOS, как наследнике классической Atari DOS 2.x. Минималистичненько, без всяких меню, чисто командная строка, минимальный размер загрузчика.
Для сборки готовой дискеты использовал тулзу «dir2atr» из пакета «Atari Tools for Win32 (https://www.horus.com/~hias/atari/#tools-win32)»
Если говорить вкратце, то принцип работы с файлами такой же как и «везде» открываем файл, читаем, закрываем.
На атари, при открытии нужно указать номер потока*16.
Для примера сделал что бы с диска читалась картинка в формате ATASCII и выводилась на экран. Экран в DOS обрезан слева на 2 колонки, пришлось картинку подрезать тоже.
https://i.postimg.cc/pLgSKTNH/1.png (https://postimages.org/)
https://i.postimg.cc/mrC5jsRF/2.png (https://postimages.org/)
пример простой как 5 копеек :)
Выделяем место под буфер
Читаем, если ошибка (файл не найден), выводим код ошибки
Если всё успешно выводим посимвольно.
import stdio
import xdos
const byte channelID = 16*2
array fileName = ["D:DINO.ATA",0x9b]
const word fileSize = 950
array fileData[fileSize]
void main() {
word i
byte status
status = openFile(fileName, XDOS_R, channelID)
if (status == XDOS_OK) {
readFile(fileData, fileSize, channelID)
closeFile(channelID)
new_line()
for i,0,to,fileSize-1 {
putchar(fileData[i])
}
} else {
putstrz("Open error:"z)
putword(status)
}
}
Имя файла «прибито», было бы не плохо разобраться с аргументами командной строки, вроде XDOS это позволяет, если я правильно понял.
Есть ещё нюанс с размером файла. Чисто гипотетически, если задать размер, например 255, а размер файла будет 24 байта, то система прочитает ровно 24 байта, даже если указать 255 в параметрах. Но остаётся вопрос с тем же выводом, как реально понять сколько же фактически было прочитано с диска. Нужно ещё разбираться.
Но начало уже положено, можно подгружать «уровни» и другую информацию с дискеты на ура ;)
тут один камрад подсказал насчет конца строки на Атари:"priwet,vestokij WORLD!{x9b}"
Поковырял тут немного XDOS. Согласно документации, после загрузки программы, с адреса XLINE ($0880) находится вся строка (имя файла + аргументы) которые набрали.
Сделал небольшую процедурку, которая копирует эту шнягу в буфер и теперь можно загружать разные файлы, указав их как аргумент:
https://i.postimg.cc/FHJxHTdF/3.png (https://postimages.org/)
https://i.postimg.cc/25R7bnhQ/4.png (https://postimages.org/)
Единственное что осталось это разобраться с размерами загружаемого файла. Чисто гипотетически конечно можно не грузится этим и грузить частями в небольшой буфер, но так не интересно :)
Это только ATASCII? poke 82,0 решат заморочку с краями.
Единственное что осталось это разобраться с размерами загружаемого файла.
возможно стоит посмотреть в
XFILE = $87D filename buffer
ещё про команду LOA пишут что
After executing the command, the Number of bytes actually loaded in $358/9
(and can be determined with the DUP command = 358)
Это только ATASCII?
Ну для примера да, а так не важно что там, может и обычный текст быть.
poke 82,0 решат заморочку с краями.
Ну как вариант :)
- - - Добавлено - - -
возможно стоит посмотреть в
XFILE = $87D filename buffer
Честно там не совсем понятно что за данные.
ещё про команду LOA пишут что
After executing the command, the Number of bytes actually loaded in $358/9
(and can be determined with the DUP command = 358)
Ну надо подумать, вообще хотелось бы предварительно знать, сколько выделять памяти. Но это только в мечтах. Размер Array должен быть статический, тупо выделил 256б вот и радуйся)
Чисто гипотетически можно выделить 128б (по размеру сектора) и сделать счётчик загрузки ;)
Короче, пошаманив немного, нашел идеальный вариант. Методом научного тыка (из дампа памяти) нашел интересный адрес $0028/29 а потом в описании памяти атари увидел, что здесь хранится количество переданных/принятых байт через SIO. Так что вопрос с точностью быстро решился.
Вариант с адресами $358/9 не проканал, поскольку это используется при команде 40 (если я правильно понял) загрузчика бинарных файлов (исполняемых). И там ничего нет при загрузке через команду 7.
Переименовал файл в XV.COM, так как задолбало набирать длинное название с расширением, а XEX XDOS не понимает :(
Ну и поправил некоторые ляпы с $9b (перенос строки) и на время отображения отключаю смещение (poke 82,0). Буфер сделал 1024 байта, если сделать меньше (например 255), то видно как частями грузится картинка :)
Так же встречается ESC код $1b (в картинке ATARI600) поправил, теперь всё збс!
Есть косяк с US2.ATA не могу понять почему на середине картинки позицию швыряет в начало экрана o_O
Ещё почему-то не зависимо от того нашелся ли файли или нет(заблокирован) из $0343 возвращается код 01 - ошибок нет. Надо копать.
Ну а так в целом минималистичный вьювер ATASCII готов :)
https://i.postimg.cc/15PS37NZ/5.png (https://postimages.org/)
https://i.postimg.cc/m2wsz3Q1/6.png (https://postimages.org/)
https://i.postimg.cc/L88MzqTC/7.png (https://postimages.org/)
Решил тут ещё немного поколупаться с DOS, в результате чего родился плеер треков в формате MPT (Atari Music ProTracker) да да, всем так нравилось это слово, что протрекер есть везде :)
https://i.postimg.cc/fbDwHdqk/8.png (https://postimages.org/)
Сначала загружается сама программа, затем бинарь MPT-плеера (в будущем можно сделать детект и подгружать разные плееры).
В качестве аргумента указываем имя музыки.
На бордюре такты, по любой клавише выход.
Из интересного, в Millfork есть пример для этого плеера, но он немного некорректен. Во первых исходный XEX занимает аж 38кб, поскольку сама программа и плеер с музыкой «размазаны» по памяти, выгружается такой огромный брикет. А во вторых, пропускаются 6 байт при импорте файлов:
const array player @ ADDRPLA = file("data/mpt_player.obj", 6)
Почему их было не обрезать сразу при создании мне не ясно. В принципе я нашел плеер MPT в исходниках, так что можно подумать об оптимизации.
Кроме того походу пьесы автор не разобрался как управлять плеером, и вместо того что бы подать команду 2 (остановить) он глушит цифровые каналы (да-да плеер умеет в дигитал).
В сырках я перевёл команды плеера:
// commands, A:
// 0 - инициализация. в регистрах Y-младший и X-старший байт адреса музыкальных данных.
// 1 - воспроизвести инструмент, номер которого находится в битах 4-0 рег.X,
// в битах 7-6 рег.X - номер канала, на котором должен быть сыгран этот инструмент,
// а в рег.Y-номер ноты инструмента, с C-1 - $00, c#1 - $01.
// 2 - остановить воспроизведение музыки, без каких-либо параметров.
// 3 - воспроизвести паттрен, номер которого находится в битах 5-0 рег.X,
// в битах 7-6 рег.X - номер канала, а рег.Y - транспозиция канала.
// 4 - начать воспроизведение музыки. В рег.X - номер позиции начала, а рег.Y - биты 0-3 какой из
// каналов должен быть выключен (0 - 3й, 1 - 2й, 2 - 1й, 3 - 0й канал = 1 выключен)
// 5 - воспрозвести цифровой семпл, в регистрах Y-младший и X-старший байт адреса таблици, в которой
// находится список адресов расположения семплов.
// 6 - воспроизведение цифровой музыки, в рег.X bit 0 = 1 - 15kHz, 0 - 8kHz
// 7 - воссоздаёт(?) цифровой семпл, номер которого в рег.Y(0-F), в рег.X bit0 - 15kHz, bit7-6 номер канала
во вторых, пропускаются 6 байт при импорте файлов:
const array player @ ADDRPLA = file("data/mpt_player.obj", 6)
Почему их было не обрезать сразу при создании мне не ясно
Вангую, что стандартный заголовок - слово $FFFF, начальный адрес, конечный адрес.
Вангую, что стандартный заголовок - слово $FFFF, начальный адрес, конечный адрес.
Ну где-то так :) Это DOS-заголовок файлов?
Итак очередная версия моего плеера под XDOS.
На этот раз она по расширению файла понимает какой тип плеера нужен, и подгружает его.
Пока этот два варианта CMC - Chaos Music Composer и MPT - Atari Music ProTracker.
Выглядит это так:
https://i.imgur.com/gzM3Fpl.png
К сожалению с MPT до конца разобраться не получилось и сменить адрес загрузки с наскока не вышло.
Однако это оказалось ещё не все проблемы, не знаю как с форматом MPT, но вот в CMC расположение «паттернов»(?)
в памяти привязывается при сохранении файла в редакторе.
Например, если у файла указано, что он загружается в область $8000, а потом его попытаться проиграть с $a000, то
мы в лучшем случае получим попёрдываение или завывание, а в худшем плеер почему-то тупо повиснет.
В результате чего пришлось питать ретранслятор адресов, который искал нужный и корректировал его под адрес
загрузки.
https://i.imgur.com/rPGMYlK.png
Честно говоря я немного в шоке от того, что это приходится делать в обратную сторону. Видимо спектрум разбаловал вменяемой логикой ;)
Логично же, что первый раз плеер вызывает инициализацию и может табличку адресов подкорректировать. Но нет, всё жОска прибито.
Подозреваю что в MPT такая же фигня.
С привязкой по адресам у плееров вообще беда. К счастью, утилиты были у Mad Assembler.Я так страдал с .RMT, а потом плюнул, и стал ориентироваться на занятые адреса $4000-сколько там.
Поковырял я тут тему со шрифтами, в принципе ничего «сложного» как опосался andrews не оказалось.
Достаточно сменить значение по адресу 756, на старший байт расположения нового шрифта в памяти.
Заодно дописал сохранение файлов, и закомментированный кукусок кода, который сохраняет на дискету оригинальный шрифт атари из ROM, размером 1024 байта.
Ну и накидал в образ прикольных ещё шрифтов, при желании можно дорисовать русские символы.
Русский вводится переключением капса вместо мелких букв.
https://i.imgur.com/4okHkAE.png
https://i.imgur.com/icAZc5b.png
https://i.imgur.com/018zUmZ.png
https://i.imgur.com/WR3J3OU.png
Продолжая разбираться в премудростях хранения графических данных решил написать просмотрщик для картинок в формате MIC.
Формат простой «обычный» bitmap без премудростей в виде чанков, но как оказалось со своими нюансами. Замучав народ на зарубежном форуме мне таки удалось родить нечто удобоваримое.
Из особенностей:
1) Antic не умеет делеко в раму, потому битмап должен грузиться поближе, в идеале с адреса $2000
2) Antic не умеет адресовать одновременно больше 4к, из-за этого нужно в Display List для каждой строчки устанавливать новый адрес данных
3) Из-за первого и второго пришлось грузить файл хитрым образом, блоками по 3840, 3840 и 1924 в адреса $2000, $3000 и $4000 соответственно.
Пока не сделал этого на экране творился дурдом и мусор.
Пока искал другие примеры картинок в формате MIC (кроме своего логотипа) наткнулся что он (MIC) ещё произвольного размера может быть по высоте. Пока сделал только для одного размера, но
возвращаемся к вопросу как узнать размер файла на диске и желательно в байтах?
https://i.imgur.com/Fd4TFJt.png
https://i.imgur.com/KqV2BoY.png
https://i.imgur.com/liSicJL.png
https://i.imgur.com/4ArPFtS.png
ps. подвигал немного палитру в эмуле, что бы ближе была как на моём атари.
Зачем для Display List задавать адрес для каждой строчки?
Зачем для Display List задавать адрес для каждой строчки?
Ну теоретически достаточно только для 3х блоков, а так можно задать отдельно цвета как в мультколоре на ZX ;)
Вот обычный MIC но с «расширенной» палитрой для каждой строчки
https://i.imgur.com/t612MYX.png
Dart Alver
06.01.2025, 22:44
Пытаюсь понять что с этим зверем Millforkом можно сделать, буксую на основах ))
Например в 'zxspectrum.mfk' и много где ещё:
inline asm void bell() {
? ld hl,$6A
? ld de,$105
? call $3B5
? ret
}
Не могу найти в инструкции что означает знак вопроса в данном случае.
Не могу найти в инструкции что означает знак вопроса в данном случае.
ANALогично, поэтому просто писал ASM без всяких вопросов.
Некоторый недостаток языка - это документация
https://github.com/KarolS/millfork/blob/master/docs/lang/assemblyz80.md
Any assembly opcode can be prefixed with ?, which allows the optimizer change it or elide it if needed. Opcodes without that prefix will always be compiled as written.
The '!' prefix marks the statement as volatile, which means it will be a subject to certain, but not all optimizations, in order to preserve its semantics.
Dart Alver
08.01.2025, 00:20
Некоторый недостаток языка - это документация
Да с английским у меня туговато, хотя онлайн переводчики в общем то неплохо переводят, но сама документация далеко не всегда достаточно разжевана, или лежит гдето где и не найдёшь нифига.
Впрочем это почти с любой докой так. В SjASMplus тоже далеко не всё прозрачно описано, хотя там мне нравится что всё в едином файле и можно полистать страницу. ))
Any assembly opcode can be prefixed with ?, which allows the optimizer change it or elide it if needed. Opcodes without that prefix will always be compiled as written.
The '!' prefix marks the statement as volatile, which means it will be a subject to certain, but not all optimizations, in order to preserve its semantics.
Да этот абзац как-то проглядел .
Перевод онлайн:
Любой код операции сборки может иметь префикс ?, что позволяет оптимизатору изменить его или исключить при необходимости. Коды операций без этого префикса всегда будут компилироваться так, как написано.
'!' префикс помечает оператор как изменчивый, что означает, что он будет подвергаться определенным, но не всем оптимизациям, чтобы сохранить его семантику.
Честно не представляю каким образом оптимизатор будет чтото менять в готовых ассемблерных процедурах и по какому принципу исключать. По поводу '!' вообще непонятно. Похоже это всё типа задел на будущее.
Честно не представляю каким образом оптимизатор будет чтото менять в готовых ассемблерных процедурах и по какому принципу исключать. По поводу '!' вообще непонятно. Похоже это всё типа задел на будущее.
Оптимизатор иногда выкидывает кунштюки, полюбоваться на них можно, добавив ключ -s, чтобы получить .asm. С параметрами ? и ! не разбирался. Спрошу при случае.
- - - Добавлено - - -
Ответ ттакой:
Насколько я помню, модификаторы работают так,
? - эту строку компилятор может оптимизировать, например выбросить, если это ? RET например, и функция инлайнится/ Но это на усмотрение оптимизатора
! - это кажется запрещает оптимизацию этой строчки (могу быть неправ)
Так что аккуратнее с оптимизацией.
BelaLugoci
07.03.2025, 10:38
2) Antic не умеет адресовать одновременно больше 4к, из-за этого нужно в Display List для каждой строчки устанавливать новый адрес данных
только для строки следующей за границей в 4К
только для строки следующей за границей в 4К
Ну да, не строчки, а блока. Не так немного выразился ;)
Powered by vBulletin® Version 4.2.5 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot