|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
I figured out why using the debugger memory view to change the TMS9918 registers doesn't work. so I try to set the TMS registers by hand with the debugger memory view, but it doesn't have any effect. Because when you do it with the debugger memory view, it doesn't update the corresponding member variables. So not only do you have to set the m_Regs[x] variable, you also have to change the member variables. In the file src/devices/video/tms9928.cpp when you write the registers with tms9928a_device::change_register, it updates other variables inside the driver, so for register 0, it will update m_color and m_pattern. Likewise for other registers.
void tms9928a_device::change_register(uint8_t reg, uint8_t val)
{
...
switch (reg)
{
case 0:
/* re-calculate masks and pattern generator & colour */
if (val & 2)
{
m_colour = ((m_Regs[3] & 0x80) * 64) & (m_vram_size - 1);
m_pattern = ((m_Regs[4] & 4) * 2048) & (m_vram_size - 1);
update_table_masks();
}
else
{
m_colour = (m_Regs[3] * 64) & (m_vram_size - 1);
m_pattern = (m_Regs[4] * 2048) & (m_vram_size - 1);
}
m_mode = ( (m_reva ? (m_Regs[0] & 2) : 0) | ((m_Regs[1] & 0x10)>>4) | ((m_Regs[1] & 8)>>1));
if ((val ^ prev) & 1)
update_backdrop();
if (TRACE_MODE) logerror("TMS9928A('%s'): %s\n", tag(), modes[m_mode]);
break;
So I load my vram dump into the TMS. The values to load into the registers are as follows:
reginitarray = {2,194,14,255,3,63,3,1}; for index,val in pairs(reginitarray) do print(index-1,string.format("%x",val)) end
0 2
1 c2
2 e
3 ff
4 3
5 3f
6 3
7 1
so I set by hand with the debugger: TMS9918A VDP/:sl4:arcbd:arcbd_tms/0/m_Regs[0] to 2 TMS9918A VDP/:sl4:arcbd:arcbd_tms/0/m_Regs[1] to c2 TMS9918A VDP/:sl4:arcbd:arcbd_tms/0/m_pattern to 0 (address of the pattern table) TMS9918A VDP/:sl4:arcbd:arcbd_tms/0/m_colour to 2000 (address of the color table) TMS9918A VDP/:sl4:arcbd:arcbd_tms/0/m_nametbl to 3800 (address of the name table) TMS9918A VDP/:sl4:arcbd:arcbd_tms/0/m_mode to 2 (graphics mode 2) then I can see the bitmap display. and if I further set: TMS9918A VDP/:sl4:arcbd:arcbd_tms/0/m_spritepattern to 1800 TMS9918A VDP/:sl4:arcbd:arcbd_tms/0/m_spriteattribute to 1f80 then I can see the sprites. And if you want some weird effects, just set m_pattern to 1 to 7 (something you could never have on real hardware) or to 1800 (where the sprite patterns are). I can see a table with the items in lua but it's just a list of items with the corresponding number.
for i,j in pairs(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items) do print(i,j) end
1/0/m_start.seconds 610
0/0/m_start.seconds 605
0/m_clock_scale 439
0/m_Regs[6] 437
0/m_pattern 448
0/m_colour 441
0/m_colourmask 442
0/m_palette 446
0/m_patternmask 449
0/m_Regs[7] 440
0/m_spriteattribute 450
0/m_spritepattern 451
0/m_FifthSprite 428
0/m_nametbl 445
0/m_Regs[1] 432
0/m_Regs[0] 431
0/0/m_enabled 594
1/0/m_enabled 602
1/0/m_start.attoseconds 609
0/0/m_start.attoseconds 601
1/0/m_param 606
0/0/m_param 598
0/m_ReadAhead 429
0/m_Regs[2] 433
0/m_unscaled_clock 452
1/00000000-0000ffff 673
1/0/m_period.seconds 608
0/0/m_period.seconds 600
0/m_Regs[4] 435
0/m_StatusReg 444
0/m_INT 427
1/0/m_expire.attoseconds 603
0/m_latch 447
0/0/m_expire.seconds 596
1/0/m_expire.seconds 604
0/0/m_period.attoseconds 599
0/m_clock 438
0/0/m_expire.attoseconds 595
1/0/m_period.attoseconds 607
0/m_mode 443
0/m_Regs[5] 436
0/m_Addr 425
0/m_Regs[3] 434
I wish that I could read/write these items with lua in the same way that I can read/write them with the debugger memory view window.
|
|
|
|
Joined: Jan 2012
Posts: 891 Likes: 17
Senior Member
|
Senior Member
Joined: Jan 2012
Posts: 891 Likes: 17 |
try emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/0/m_start.seconds"]):read(offset) or :write(offset, newval) or :read_block(byte_offset, len).
Last edited by crazyc; 10/17/17 06:17 PM.
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
Thank you, crazyc! That's exactly what I was looking for. Beauty!
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
So with emu.item I can do this: dofile("../../arcbd_load_vram.lua")
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[0]"]):write(0,2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[1]"]):write(0,0xc2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_pattern"]):write(0,0)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_colour"]):write(0,0x2000)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_nametbl"]):write(0,0x3800)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_mode"]):write(0,2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_spritepattern"]):write(0,0x1800)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_spriteattribute"]):write(0,0x1f80) There's a couple of other properties of emu.item that are interesting too, like .size and .count that are interesting to examine. Item "0/m_pattern" has a size of 2 and count 1 while item "0/m_Regs[0]" has size of 1 and count 1. Item "1/00000000-0000ffff" has a size of 1 and count 65536, and I can read/write into the vram with it. Very cool. This lua engine is awesome! for i,j in pairs(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items) do print(i,j) end
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_pattern"]).size)
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_pattern"]).count)
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[0]"]).size)
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[0]"]).count)
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/00000000-0000ffff"]).size)
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/00000000-0000ffff"]).count)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/00000000-0000ffff"]):write(0,255)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/00000000-0000ffff"]):write(1,0xaa)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/00000000-0000ffff"]):write(2,0x55)
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/00000000-0000ffff"]):read(0))
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/00000000-0000ffff"]):read(1))
print(emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["1/00000000-0000ffff"]):read(2))
|
|
|
|
Joined: Jan 2012
Posts: 891 Likes: 17
Senior Member
|
Senior Member
Joined: Jan 2012
Posts: 891 Likes: 17 |
Right, size is the native byte width of an entry (like sizeof()) while count is number of size width words. If there are any other mame internals that you think would be useful to access from lua let me know. Also, if you haven't looked at the Scripty Things thead above, there's some neat stuff in there (and maybe post some of your stuff in it too).
Last edited by crazyc; 10/18/17 03:05 PM.
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
Thanks again, CrazyC! I am having such a blast fiddling with lua and mame. I haven't had this much fun programming for a long time. I am still learning lua but it's so forgiving. And the console has auto-completion. Awesome! TAB for the win! This is pure genius. I haven't quite figured out what the difference is between : and . According to something I read, "The colon is for implementing methods that pass self as the first parameter. So x:bar(3,4) should be the same as x.bar(x,3,4)." To start up the machine if you have the debugger active:
manager:machine().devices[":maincpu"]:debug():go()
And in trying to figure out the syntax I invariably interchange : with . print(manager:machine().devices[":maincpu"]:debug())
sol.device_debug*: 0x559857771518 but if I call the same thing, without the colon syntax, it blows with a segfault. print(manager:machine().devices[":maincpu"].debug())
Segmentation fault (core dumped) The console plug in history is only 10 entries, but we can fix that easily by changing the line in plugins/console.init.lua ln.historysetmaxlen(10) to something like 30.
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
And one of the interesting things about older systems is that you often have to write your own routines to do graphics, like linedraws on the TMS9918. Drawing lines is actually pretty easy, just plot a pixel in the pattern memory by setting a bit, and set the color byte in the color memory. emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[0]"]):write(0,2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[1]"]):write(0,0xc2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_pattern"]):write(0,0)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_colour"]):write(0,0x2000)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_nametbl"]):write(0,0x3800)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_mode"]):write(0,2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_spritepattern"]):write(0,0x1800)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_spriteattribute"]):write(0,0x1f80)
--set background to 4
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[7]"]):write(0,0xf4)
mem=manager:machine().devices[":sl4:arcbd:arcbd_tms"].spaces["vram"]
function plotpixel(screenaddr,x,y)
local byteaddr = screenaddr + math.floor(y/8) * 256 + (y % 8) + math.floor(x/8) * 8
if x>=0 and x <=255 and y>=0 and y <=191 then
mem:write_u8(byteaddr,mem:read_u8(byteaddr)| (1 << (7-(x%8))))
end
end
function plotcolor(screenaddr,x,y,colorfg)
local byteaddr = screenaddr + math.floor(y/8) * 256 + (y % 8) + math.floor(x/8) * 8
if x>=0 and x<=255 and y>=0 and y<=191 then
--foreground single color
mem:write_u8(byteaddr,(mem:read_u8(byteaddr)& 0x0) | (math.floor(colorfg) << (4)) )
end
end
function deltasign(x)
if x<0 then return -1
elseif x==0 then return 0
elseif x>0 then return 1
else return 0
end
end
function linedraw(x1,y1,x2,y2,colorfg)
-- using basic code converted to lua from:
-- https://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm
--[[
1500 REM === DRAW a LINE. Ported from C version
1510 REM Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1
1520 DX = ABS(X2 - X1):SX = -1:IF X1 < X2 THEN SX = 1
1530 DY = ABS(Y2 - Y1):SY = -1:IF Y1 < Y2 THEN SY = 1
1540 ER = -DY:IF DX > DY THEN ER = DX
1550 ER = INT(ER / 2)
1560 PLOT X1,Y1:REM This command may differ depending ON BASIC dialect
1570 IF X1 = X2 AND Y1 = Y2 THEN RETURN
1580 E2 = ER
1590 IF E2 > -DX THEN ER = ER - DY:X1 = X1 + SX
1600 IF E2 < DY THEN ER = ER + DX:Y1 = Y1 + SY
1610 GOTO 1560
--]]
x1 = math.floor(x1)
x2 = math.floor(x2)
y1 = math.floor(y1)
y2 = math.floor(y2)
dx = x2-x1
dy = y2-y1
sx = deltasign(dx)
sy = deltasign(dy)
local x = x1
local y = y1
local adx = math.abs(dx)
local ady = math.abs(dy)
local er,e2
if adx > ady then er = adx
else er = - ady
end
er = math.floor(er / 2)
while 1 do
plotpixel(0,x,y)
plotcolor(8192,x,y,colorfg)
if x == x2 and y == y2 then return end
e2 = er
if e2 > -adx then er = er - ady; x = x + sx end
if e2 < ady then er = er + adx; y = y + sy end
if x<0 or x > 255 or y < 0 or y > 191 then return end
end -- while
end -- function
function clearscreentms()
tms= manager:machine().devices[":sl4:arcbd:arcbd_tms"]
mem = tms.spaces["vram"]
local addr
for addr = 0,6143 do mem:write_u8(addr,0) end
end
function circlerandomcolor(step,size)
local i
for i=0,360,step do linedraw(128,96,128+math.cos(i/360*2*math.pi)*size,96+math.sin(i/360*2*math.pi)*size,math.floor(math.random()*15)) end
end
function initpatterntms()
local pat
for pat = 0,768-1 do
mem:write_u8(pat+0x3800,pat % 256)
end
end
clearscreentms()
initpatterntms()
for i = 0,255,16 do linedraw(i,0,0,192,math.floor(i/16)) end
circlerandomcolor(1,50)
for i = 0,255,16 do linedraw(i,0,255,191,math.floor(i/16)) end
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
I wanted to see if I could rip atari 2600 graphics from the game Stampede, so I wrote a little lua script to dump the ram from the 2600. I didn't know how much to grab, so I went for 4k. I now know that Stampede is a 2k cartridge. mem=manager:machine().devices[":maincpu"].spaces["program"]
-- read ram and save to a file
outfile = assert(io.open("2600_dump_file", "wb"))
for i=0x1000,0x2000-1 do
outfile:write(string.char(mem:read_u8(i)))
end
assert(outfile:close())
and once you have the 2600_dump_file saved, you can run this script on the apple2e driver with -sl4 arcbd which will make the following display: The horse animates and you can move it left right/up and down. I always wondered why the legs of the horse had an interlaced effect. That's because of the HMOVEs so the legs can split and display wider than the 8 pixels in a byte. -- ==============================================================
-- read datablock from a file and close it
infile = assert(io.open("2600_dump_file", "rb"))
datablock = infile:read("*all")
assert(infile:close())
-- ====================================================================
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[0]"]):write(0,2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[1]"]):write(0,0xc2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[1]"]):write(0,0xc3) -- dbl size
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_pattern"]):write(0,0)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_colour"]):write(0,0x2000)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_nametbl"]):write(0,0x3800)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_mode"]):write(0,2)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_spritepattern"]):write(0,0x1800)
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_spriteattribute"]):write(0,0x1f80)
--set background to 4
emu.item(manager:machine().devices[":sl4:arcbd:arcbd_tms"].items["0/m_Regs[7]"]):write(0,0xf4)
mem=manager:machine().devices[":sl4:arcbd:arcbd_tms"].spaces["vram"]
function plotpixel(screenaddr,x,y)
local byteaddr = screenaddr + math.floor(y/8) * 256 + math.floor(y % 8) + math.floor(x/8) * 8
if x>=0 and x <=255 and y>=0 and y <=191 then
mem:write_u8(byteaddr,mem:read_u8(byteaddr)| (1 << (7-(x%8))))
end
end
function plotcolor(screenaddr,x,y,colorfg)
local byteaddr = screenaddr + math.floor(y/8) * 256 + math.floor(y % 8) + math.floor(x/8) * 8
if x>=0 and x<=255 and y>=0 and y<=191 then
--foreground single color
mem:write_u8(byteaddr,(mem:read_u8(byteaddr)& 0x0) | (math.floor(colorfg) << (4)) )
end
end
function deltasign(x)
if x<0 then return -1
elseif x==0 then return 0
elseif x>0 then return 1
else return 0
end
end
function linedraw(x1,y1,x2,y2,colorfg)
-- using basic code converted to lua from:
-- https://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm
x1 = math.floor(x1);x2 = math.floor(x2);y1 = math.floor(y1);y2 = math.floor(y2)
dx = x2-x1; dy = y2-y1
sx = deltasign(dx); sy = deltasign(dy)
local x = x1; local y = y1
local adx = math.abs(dx)
local ady = math.abs(dy)
local er,e2
if adx > ady then er = adx
else er = - ady
end
er = math.floor((er / 2)+0.5) -- INT rounding because math.floor rounding doesn't work for 1 pixel lines
while 1 do
plotpixel(0,x,y)
plotcolor(8192,x,y,colorfg)
if x == x2 and y == y2 then return end
e2 = er
if e2 > -adx then er = er - ady; x = x + sx end
if e2 < ady then er = er + adx; y = y + sy end
if x<0 or x > 255 or y < 0 or y > 191 then print("hit edge",x1,y1,x2,y2) return end
end -- while
end -- function
function drawbox(x1,y1,x2,y2,col)
linedraw(x1,y1,x2,y1,col)
linedraw(x2,y1,x2,y2,col)
linedraw(x2,y2,x1,y2,col)
linedraw(x1,y2,x1,y1,col)
end
function clearscreentms()
tms= manager:machine().devices[":sl4:arcbd:arcbd_tms"]
mem = tms.spaces["vram"]
local addr
for addr = 0,6143 do mem:write_u8(addr,0) end
end
function initpatterntms()
local pat
for pat = 0,768-1 do
mem:write_u8(pat+0x3800,pat % 256)
end
end
function initcolortms(fg,bg)
for addr = 0,6143 do mem:write_u8(addr+8192,bg|(fg<<4)) end end
function clstms()
clearscreentms()
initpatterntms()
initcolortms(15,4)
end
clstms()
function reversebits(x)
local outbyte = 0
for bit=0,7 do
if(x & (1<<bit))~=0 then outbyte = outbyte | (1<<(7-bit)) end
end
return outbyte
end
function draw2600intoscreendirect()
for i=0,4096-1 do
mem:write_u8(i,reversebits(string.byte(datablock,(i+1)))) -- datablock index starts at 1
end
end
clstms()
function draw2600intoscreen()
xpos = 0; ypos = 0
for i = 4096-1,4096-2048-1,-1 do
for bit=0,7 do
if (reversebits(string.byte(datablock,(i+1))) & (1<<bit))~=0 then linedraw(xpos+bit,ypos,xpos+bit,ypos,7) end
end
ypos = ypos + 1
if ypos >= 128+16 then ypos = 0; xpos = xpos + 16; end
end
end
clstms()
draw2600intoscreen()
function stampededogie(p8d,p8f)
--linedraw(xpos,ypos,xpos,ypos,1)
for offset = 0xf,1,-1 do
grp1 =p8f+offset
hmove=p8d+offset-1
for bit=0,7 do
if (reversebits(string.byte(datablock,(grp1+1))) & (1<<bit))~=0 then linedraw(xpos+bit,ypos,xpos+bit,ypos,7) end
end
hmoveval = (string.byte(datablock,(hmove+1))>>4)
if hmoveval >= 8 then hmoveval = hmoveval - 16 end
xpos = xpos - hmoveval
ypos = ypos + 1
if ypos >= 128+64 then ypos = 128+32; xpos = xpos + 16; end
end
end
xpos = 32; ypos = 128+48; stampededogie(0x6c9,0x67d);
xpos = 32+1*16; ypos = 128+48; stampededogie(0x6c9,0x66e);
xpos = 32+2*16+6;ypos = 128+48; stampededogie(0x6ac,0x68b)
function stampede_horse(p8b,p8d,p8f)
--p8b is ptr to hmp0, p8d is ptr to nusiz0, p8f is ptr to grp0
xpos = xpos + 32
ypos = 128+24
for offset=0x19,1,-1 do
grp0 =p8f+offset
hmove=p8b+offset-1 -- hmove happens to "next line"
nusiz=p8d+offset
-- follows the atari 2600 stampede code which ORs these 2 together
nusiz=string.byte(datablock,(nusiz+1)) | (string.byte(datablock,(hmove+1+1))&5)
nusiz=nusiz & 0xd
if (nusiz & 7) == 5 then dbl=2 else dbl=1 end
for bit=0,7 do
if (reversebits(string.byte(datablock,(grp0+1))) & (1<<bit))~=0 then
linedraw(xpos+bit*dbl,ypos,xpos+(bit+1)*dbl-1,ypos,7+dbl)
end
end
hmovedelta = (string.byte(datablock,(hmove+1))>>4)
if hmovedelta >= 8 then hmovedelta = hmovedelta - 16 end
xpos = xpos - hmovedelta
ypos = ypos + 1
if ypos >= 128+64 then ypos = 128+24; xpos = xpos + 32; end
end
end
xpos=64; stampede_horse(0x74d,0x6c7,0x71a);
xpos=64+1*32; stampede_horse(0x766,0x6c7,0x700);
xpos=64+2*32; stampede_horse(0x74d,0x6c7,0x700);
xpos=64+3*32; stampede_horse(0x77f,0x6c3,0x734);
function drawblock(addr,offset1,offset2)
ypos0 = ypos
for i=addr+offset1,addr+offset2,-1 do
for bit=0,7 do
if (reversebits(string.byte(datablock,(i+1))) & (1<<bit))~=0 then
linedraw(xpos+bit,ypos,xpos+bit,ypos,10)
end
end
ypos = ypos + 1
end
xpos = xpos + 8
ypos = ypos0
end
function stampede_activision()
drawblock(0x668,6,0) -- act
drawblock(0x660,6,0) -- iv
drawblock(0x658,6,0) -- isi
drawblock(0x650,6,0) -- on
end
xpos = 128; ypos= 128+56
stampede_activision()
function stampede_skull()
drawblock(0x69b,9,1)
end
xpos = 64;ypos = 128+20
stampede_skull()
function stampede_0123456789()
for num = 0,9 do
drawblock(0x600+num*8,6,0)
end
end
xpos = 0; ypos = 128+30; stampede_0123456789()
function xytoaddress(x,y)
--print(x,y,math.floor(y/8)*256+(y%8)+math.floor(x/8)*8)
x = math.floor(x)
y = math.floor(y)
return math.floor(y/8)*256+(y%8)+math.floor(x/8)*8
end
for box=0,3 do drawbox(80+32*box,150,80+32*(box+1)-1,150+31,9) end
-- 4 different 16x16 blocks
bytepos=0x1800;
for box = 0,3 do
for cellx = 0,1 do for celly = 0,1 do for j = 0,1 do for i=0,15 do mem:write_u8(bytepos,mem:read_u8(xytoaddress(80+8*j+16*cellx+box*32,150+i+16*celly))); bytepos = bytepos + 1; end end end end end
spriteatt = 0x1f80
horsex = 25
horsey = 25
scale = 2
function setsprite(sprnum,sprimgnum)
for celly = 0,1 do
for cellx = 0,1 do
mem:write_u8(spriteatt + cellx*2*4 + celly*4 + 0, horsey+16*celly*scale)
mem:write_u8(spriteatt + cellx*2*4 + celly*4 + 1, horsex+16*cellx*scale)
mem:write_u8(spriteatt + cellx*2*4 + celly*4 + 2,(cellx * 2 + celly)*4+16*sprimgnum)
mem:write_u8(spriteatt + cellx*2*4 + celly*4 + 3, 11)
end
end
end
setsprite(0,0)
dispatch_list={}
function frame_dispatcher()
for index,my_func in pairs(dispatch_list) do my_func() end
end
function dispatch_list_remove(a_func)
for my_index,my_func in pairs(dispatch_list) do if my_func == a_func then table.remove(dispatch_list,my_index) end end
end
function print_dispatch_list() for my_index,my_func in pairs(dispatch_list) do print(my_func) end end
if already_registered_frame_dispatcher == nil then
emu.register_frame(frame_dispatcher);
already_registered_frame_dispatcher = 1
end
function cld()
dispatch_list = {}
end
delaycounter1 = 0
spriteimageseq = {0,1,2,1}
spriteimageseqnum = 1
function every_frame()
-- everydelay(1,delaycounter1)
delaycounter1 = (delaycounter1+1)%5
if delaycounter1 == 0 then
spriteimageseqnum = (((spriteimageseqnum + 1)-1) % #spriteimageseq)+1
end
inp = manager:machine():input()
if inp:code_pressed(inp:code_from_token("KEYCODE_UP")) then
horsey = horsey - 2
end
if inp:code_pressed(inp:code_from_token("KEYCODE_DOWN")) then
horsey = horsey + 2
end
if inp:code_pressed(inp:code_from_token("KEYCODE_RIGHT")) then
horsex = horsex + 2
end
if inp:code_pressed(inp:code_from_token("KEYCODE_LEFT")) then
horsex = horsex - 2
end
setsprite(0,spriteimageseq[spriteimageseqnum])
end
table.insert(dispatch_list,every_frame)
|
|
|
|
Joined: Mar 2001
Posts: 17,217 Likes: 234
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,217 Likes: 234 |
Coming soon.... It actually works except for detecting slot 6 and dropping the speed right now, so obviously the Disk II is unhappy with that
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
I finally figured out how to read the apple joystick from lua. -- this is a little function to print a table
function printt(a) local i,j; for i,j in pairs(a) do print(i,j) end end
printt(manager:machine():ioport().ports)
:X5 sol.ioport_port*: 0x55d3d11cd778
:joystick_1_y sol.ioport_port*: 0x55d3d11cd7f8
:X3 sol.ioport_port*: 0x55d3d11d2fa8
:keyb_special sol.ioport_port*: 0x55d3d11cd958
:joystick_buttons sol.ioport_port*: 0x55d3d11cd9c8
:joystick_2_y sol.ioport_port*: 0x55d3d11cda38
:X7 sol.ioport_port*: 0x55d3d11cd698
:joystick_2_x sol.ioport_port*: 0x55d3d11cdaa8
:a2_config sol.ioport_port*: 0x55d3d11cd5b8
:X4 sol.ioport_port*: 0x55d3d11cd7b8
:joystick_1_x sol.ioport_port*: 0x55d3d11cd548
:X2 sol.ioport_port*: 0x55d3d52ee878
:X1 sol.ioport_port*: 0x55d3d52ee8f8
:X8 sol.ioport_port*: 0x55d3d11cd628
:X0 sol.ioport_port*: 0x55d3d11d2cd8
:X6 sol.ioport_port*: 0x55d3d11cd708 and if you look at the apple2e.cpp code, you can see that it maps right up to this:
PORT_START("joystick_buttons")
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_PLAYER(1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON1)
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_PLAYER(1) PORT_CODE(KEYCODE_ENTER_PAD)PORT_CODE(JOYCODE_BUTTON2)
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON1)
so to read the buttons you can do: print(manager:machine():ioport().ports[":joystick_buttons"]:read())
0 and to test it in an if statement: if (manager:machine():ioport().ports[":joystick_buttons"]:read() & 0x10) ~= 0 then
-- button 1 pressed
end
if (manager:machine():ioport().ports[":joystick_buttons"]:read() & 0x20) ~= 0 then
-- button 2 pressed
end
The joystick axes come in under the names "joystick_1_x" and "joystick_1_y" Looking at apple2e.cpp we have:
static INPUT_PORTS_START( apple2_joystick )
PORT_START("joystick_1_x") /* Joystick 1 X Axis */
PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X) PORT_NAME("P1 Joystick X")
PORT_SENSITIVITY(JOYSTICK_SENSITIVITY)
PORT_KEYDELTA(JOYSTICK_DELTA)
PORT_CENTERDELTA(JOYSTICK_AUTOCENTER)
PORT_MINMAX(0,0xff) PORT_PLAYER(1)
PORT_CODE_DEC(KEYCODE_4_PAD) PORT_CODE_INC(KEYCODE_6_PAD)
PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH)
PORT_START("joystick_1_y") /* Joystick 1 Y Axis */
PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y) PORT_NAME("P1 Joystick Y")
PORT_SENSITIVITY(JOYSTICK_SENSITIVITY)
PORT_KEYDELTA(JOYSTICK_DELTA)
PORT_CENTERDELTA(JOYSTICK_AUTOCENTER)
PORT_MINMAX(0,0xff) PORT_PLAYER(1)
PORT_CODE_DEC(KEYCODE_8_PAD) PORT_CODE_INC(KEYCODE_2_PAD)
PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH)
and in lua we can read it with:
print(manager:machine():ioport().ports[":joystick_1_x"]:read())
128
print(manager:machine():ioport().ports[":joystick_1_y"]:read())
128
Note that to get the input events for the joystick movement and buttons, the apple2e window must be selected. So if you do a print(manager:machine():ioport().ports[":joystick_buttons"]:read()) from the lua console you will get zero unless you select the apple2e window, hold the joystick button(s), click on the lua console window and then do your print statement. What's kind of interesting is that with the focus taken away from the window, the joystick and buttons will center or release but won't move away from center.
|
|
|
Forums9
Topics9,320
Posts121,944
Members5,074
|
Most Online1,283 Dec 21st, 2022
|
|
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!
|
|
|
|