<bslsk05>
'Controllers - Super Nintendo Entertainment System Features Pt. 08' by Retro Game Mechanics Explained (00:23:58)
<clever>
this explains how the controllers, mouse, multi-tap, and light gun all work on the snes
<clever>
and the timestamp skips to the lightgun
heat has quit [Remote host closed the connection]
<mrvn>
clever: I need the physical part, not the registers / software
<geist>
i always assumed they looked at the timing of the electron gun
<clever>
yeah, thats how i believe it works as well
<geist>
and thus only worked on CRTs but from what i understand the NES one woud just blink the screen and show a white box for one frame
<clever>
and the calibration deals with any sub-frame delay within your display
<geist>
if the gun 'saw' the box you were pointing at it
<mrvn>
it needs to trigger an IRQ when the CRT beam lights up the light sensor in the gun.
<zid>
yea which is why pointing it at a lightbulb worked :P
<mrvn>
I wonder if I can make it trigger from the reflected light of the laser projector and then somehow figure out where the point was from the delay since I send a frame to the projector to refresh.
<zid>
'yep, white pixel'
<zid>
The psx one uses the retrace
<zid>
that's why it has a weird loopback from the AV out
<clever>
in the case of the c64/snes, the gpu will latch the current xy when you hit a special latch pin
<mrvn>
zid: a lightbulb wouldn't got off at 50Hz.
<clever>
and then you just apply a fixed offset for calibration
<mrvn>
no such latch for me,.
<clever>
then you need to do it in software, and deal with irq jitter
<mrvn>
I'm not even sure the projector always scans the full screen. Maybe it skips dark parts or something. Timing for the position might not be linear.
sonny has quit [Ping timeout: 252 seconds]
Vercas has quit [Ping timeout: 240 seconds]
gog has quit [Ping timeout: 246 seconds]
Vercas has joined #osdev
<mrvn>
I'm starting to get the hang of paramter packs in C++
<bslsk05>
'Pac-Man Ghost AI Explained' by Retro Game Mechanics Explained (00:19:33)
<geist>
i always assumed they just all homed in on you
<zid>
you'd have noticed if that's what they did
<zid>
because it'd be super boring and obvious that that's what they were doing
<zid>
It's hard to figure out they all have a different AI, but if you play it for a little bit it's obvious they're not just following
<geist>
yah i rarely played it and/or i played the 2600 version which may have been dumber
<geist>
also i assume ms pac man's AI is different since it's supposedly non deterministic
<zid>
yea I have no clue bout the spin off? sequel?
<zid>
Not sure what bucket you'd put ms. pac-man in
<geist>
i think it's the direct sequel
<zid>
It is mechanically but the only thematic aspect is different
<zid>
so it'd be like if mario 64 was the direct 'sequel' to ocarina of time, using its engine
<geist>
well, sure. but it's the direct sequel in the sense that it's officially the second game in the franchise, etc
<geist>
but yeah the code base is probably totally different or whatnot
<zid>
Right that's a good way of putting it
<zid>
it's the 2nd entry in the franchise
nyah has quit [Ping timeout: 258 seconds]
heat has joined #osdev
sonny has joined #osdev
sonny has left #osdev [#osdev]
<mrvn>
geist: implementing PacMan true to the original sounds like a nice project. Plus an AI to play it.
<jjuran>
geist: The 2600 "Pac-Man" was terrible.
<jjuran>
TRON: Legacy is the sequel to TRON. Doesn't mean the technology used was at all similar :-)
<mrvn>
When I understand the RPi 3D interface I want to re-implement Populous.
papaya has joined #osdev
<geist>
jjuran: yeah i think it was a crappy reimplementation to try to fit in the hardware. i suspect it just followed blinky's algorithm, which would be easy enough to implement
<geist>
oh gosh it was much worse than i thought. i only see 2 ghosts
<zid>
I have it somewhere
<zid>
It had more than 2 ghosts
<zid>
but maybe 1 of them had to be dead in order for there to be 3? :P
<geist>
dunno was just watching smoe longplay on youtube
<geist>
or maybe itw as a difficultly selector feature
<zid>
ooh yea
<zid>
Forgot about the damn hardware switch for that
<heat>
breaking news: poltergeist wants more ghosts
<zid>
He's finally raising his undead armies
<heat>
>undead
* heat
resists turning this into #darksouls again
<zid>
I said undead not undying, to be fair
<zid>
heat do you think maybe that the 2600 pacman might be a pretty... hollow... experience?
FireFly has quit [Ping timeout: 260 seconds]
<heat>
yes, but my giant dad disagrees
<zid>
I don't have a giant dad :( He's really short like a minature german pony, you might say he's approximately a zweihander.
xenos1984 has quit [Read error: Connection reset by peer]
jafarlihi has joined #osdev
heat_ has joined #osdev
heat has quit [Read error: Connection reset by peer]
heat_ is now known as heat
<heat>
linux just removed x86 a.out support
<heat>
how will I run my 1992 programs now?
<j`ey>
by using an older kernel!
<jafarlihi>
How to git gud? I have dedicated 8 hours a day to osdev since a week ago but I barely can do anything outside of copying tutorial codes
<sbalmos>
like everything else in here - qemu :D
<heat>
j`ey are you high memory in or high memory out?
<heat>
jafarlihi, that's because you spent those 8 hours copying tutorials
<jafarlihi>
heat: What do you suggest?
<heat>
learn it at your own pace and understand *everything* fully
<j`ey>
heat: I cant tell if thats a joke im missing, im 64bit anyways, noHIGHMEM here
<heat>
j`ey, no that's an actual debate right now
<j`ey>
dont some things.. just need it?
<heat>
some people including linus want to remove highmem and tell people that need more than 800MB on a 32-bit arch to run older kernels
<heat>
some arm people are upset, so yeah
<heat>
apparently they're still doing 32-bit ARM machines with lots of memory
<j`ey>
yeah.. maybe in a few years
<j`ey>
(remove it in a few years I mean)
<heat>
oh oops hahaha I read a mailing list thread from 2020
<heat>
am I a time traveler?
<j`ey>
the power of archives!
<heat>
i like highmem, it's an interesting thing
xenos1984 has joined #osdev
<psykose>
is highmem the memory implementation you come up with while being really high
<heat>
no
<heat>
i know that's a joke, but it's accessing memory > 800MB in the kernel
<heat>
the first 800 or so are mapped directly, so they're not highmem
<mrvn>
j`ey: If I had drunken 64 Bit I wouldn't understand anything, too.
<j`ey>
(it's 768MB right?)
<heat>
just mapping it doesn't work because you can run out of mappings and it's slow
<j`ey>
and then you have some 'temporary' mappings for other bits of memory (aka outside of the 800MB)
<heat>
j`ey, 896MB
<mrvn>
heat: Why is highmem even a discussion? Doesn't then kernel address space separation mitigation make that distinction obsolete?
<heat>
at least in 32-bit x86
<heat>
mrvn, no. how would that affect things?
<mrvn>
Just run the kernel in lowmem with the full 4GB address space.
<heat>
how do you touch user memory then?
<heat>
in a *performant* way
<mrvn>
Should be a small change to fix up copy_to_user and copy_from user to use temporary mappings.
<heat>
get_user_pages is slow as balls
<mrvn>
No way around it with address space separation
<heat>
yes there is
<j`ey>
heat: maybe its 768 for arm32 then
<heat>
the separation is only in usermode
<heat>
the kernel still has the lower user bits mapped
<heat>
right now copy_(to/from)_user are literally just memcpies with some fallback "if exception" code
<mrvn>
heat: right now, not with a low mem kernel
<heat>
right
<heat>
and the only way to fix those to use temporary mappings would be to do get_user_pages(again, slow as balls) and then map it (slow as balls part 2)
<j`ey>
heat: if exception is cool code
psykose has quit [Remote host closed the connection]
<mrvn>
Mapping the user pages shouldn't be a problem since you are reloading the page tables later. So no need to INVLPG or anything. Just a few writes to the page tables and memcpy()
<heat>
you use PCID/ASID to take a good chunk of the overhead away
<mrvn>
don't you have to get_user_pages() anyway to check the process is allowed to read/write there?
<heat>
mov %cr3 isn't a tlb flush in those contexts
<heat>
no
psykose has joined #osdev
<heat>
again, it's just a memcpy with a goto if it faults
<mrvn>
that would allow memcpy() of kernel memory. You have to at least check for x < 0x80000000
<heat>
yes
<mrvn>
For me the memcpy would go wrong for pages mapped user-read | kernel-write.
<heat>
you can't do that though?
<mrvn>
ARM can
<heat>
the kernel can't
<mrvn>
what can't the kernel? map pages "user-read | kernel-write"?
<heat>
it's not apart of its interfaces
<heat>
definitely not mmap(), and I don't believe there's an internal API for that either
<mrvn>
it is for me. that's why I said "For me"
<heat>
ok
<mrvn>
but anyway: Why 800MB? what happened to the 2:2 split?
<heat>
first, it's not a 2:2 split but a 3:1 split
<heat>
then that last GB is split between the lowmem (896MB) and the rest
<heat>
the rest including ioremaps and kmaps (the highmem thing)
<mrvn>
iirc there used to be 1:3, 2:2 and 3:1 split options.
<heat>
*shrug*
jafarlihi has quit [Ping timeout: 246 seconds]
bauen1 has quit [Ping timeout: 246 seconds]
blockhead has quit []
blockhead has joined #osdev
<geist>
I think over time 3:1 or even 3.5:.5 became more ‘standard’ at least in x86 kernels
<geist>
Mostly because people wanted more and more user space processes
<mrvn>
x86_64 has 3.999:0.001 for 32bit
<geist>
And the kernel can in a new version bequeath user space more memory, being the primary advantage of putting the kernel in high at least
<geist>
Right
<geist>
Only 32 bit arch I know that could easily handle a pure 4:0 split is PowerPC, and that’s because when it takes an exception it drops into ‘real mode’ which implicitly disables the mmu
<geist>
So basically you put your exception vectors in physical address space and context switch to the kernel, if you so desired to have it be a separate address space
<geist>
You could still do a 2:2 or whatnot split, but for a brief period you’re ‘outside’ of the current mmu context
<moon-child>
I think some 32-bit apps broke when you gave them more than 2gb, because they were stuffing pointers in signed ints and then doing things that only worked if those ints were positive
<mrvn>
you can do the same with switching to a kernel address space (that has no userspace mapped)
<geist>
moon-child:yah i remember that being a thing when NT based systems gave you the opportunity. For a while it was an opt in, a flag on the PE binary, iirc
<geist>
mrvn:correct but you still need a little trampoline for most arches
<mrvn>
moon-child: butb that's just source that is UB.
<mrvn>
Bigger problem is that ptrdiff_t doesn't have enough bits for 4GB.
<moon-child>
mrvn: yep
<mrvn>
and ssize_t
<moon-child>
so?
<moon-child>
apps rely on ub all the time :P
<geist>
I actually remember that being a thing when I worked at Sega. We had some build system stuff that would actually push 2GB, so we had to enable the 3GB flag on the build machines and set it in the project
<mrvn>
moon-child: no app may rely on UB. Only on IDB
<moon-child>
I said nothing about whether they 'may' or not
<moon-child>
fact is they do
<mrvn>
moon-child: apps segfault and crash a lot too. Luckily the compiler warns about most of that stuff.
<moon-child>
you know how many things broke because they stuffed pointers into 'int', which stopped working on 64-bit because pointers were still 32-bit?
<mrvn>
pointers in signed ints will fail spectaculary on alpha because user space is above 4GB.
<geist>
That’s because it wasn’t actually a 32bit arch. It was very much like x32
<geist>
Well at least the NT for alpha was
<mrvn>
I mend linux on alpha. Not sure what NT for alpha used as address space
<geist>
I think hey just only mapped in <4GB and then emitted code in x32 style
<mrvn>
verry likely
<geist>
I learned this much later when they did the first ‘true’ 64bit NT with titanium
<mrvn>
long == 32bit under windows anyway.
<geist>
And then x64-64
<mrvn>
Tons of windows progs store pointers in long because surely that's the big type that fits everything, right?
<mrvn>
geist: Does fuchsia in 64bit start userspace at 4GB?
<geist>
Neon.
<geist>
Nein
<geist>
(Stupid autocorrecting client)
<raggi>
Fuchsia is always 64bit
<moon-child>
it's fuchsia, not neon
<geist>
Used to set the user space base at 16MB but i think we moved it back to 2MB because Linux :(
<moon-child>
sheesh
<j`ey>
does anything actually rely on that?
<geist>
Linux does.
papaya has quit [Quit: leaving]
<mrvn>
j`ey: rely on what?
<j`ey>
sorry I meant does anything in fuschia rely on it being 64bit
<geist>
Since as it is well known, any feature/misfeature/etc of anything quickly becomes load bearing
<geist>
Oh lots. Mostly in that we generally assume that we have 64bits to play with
<geist>
And thus design algorithms around having lots of address space to play with
<geist>
But outside of that, probably not
<j`ey>
makes sense
<mrvn>
Just having all physical memory mapped really limits you for 32bit.
<geist>
And of course the kernel assumes 64bit so it can generally not worry about a tight address space
<geist>
Right
<mrvn>
(and we are back at linux only supporting 800MB)
<geist>
And also informs thing like passing 64bit values around and not worrying about it being slow
<geist>
But fuchsia had a 32bit port for the first year or so, inherited from LK
<geist>
We just decided it wasn’t worth maintaining it
<mrvn>
geist: is that so much of an issue? atomic_t can be a big problem.
<geist>
What is?
<mrvn>
64bit atomics when the cpu has no double word atomic primitive
<geist>
Right
<geist>
Stuff like going hard on time is 64bit period, etc
<geist>
Or things like 64bit object ids
<moon-child>
cmpxch8b!
<moon-child>
and double-width arithmetic is not that bad
<geist>
Actually this is sort of an issue with riscv since it doesn’t have a double word atomic
<mrvn>
Aarch64 has 128bit atomics so you can swap 2 pointers, right?
<geist>
We have a few places in the kernel that use double word atomic
<moon-child>
mrvn: yeah
<moon-child>
casp
<geist>
Yes, arm64 and x86-64 both have basically the same thing
<moon-child>
in lse, I think also armv8.2+
<geist>
Well, to be very specifically: x86-64-v2+. K8 didn’t have it, but later cpus all did
<geist>
-mcx16 i think is the feature switch for x86
<geist>
Armv8.0 implicitly has it too
<geist>
Because arm ain’t dumb. They have to at least feature match x86
<j`ey>
moon-child: FEAT_LSE is armv8.1
<moon-child>
ok
X-Scale` has joined #osdev
<geist>
8.0 also has it in the now ‘legacy’ atomics
X-Scale has quit [Ping timeout: 258 seconds]
<moon-child>
-mcx16 sort of...
<moon-child>
clang does the right thing, but gcc will emit a library call for __atomic*
<geist>
Youcan disable that with a switch
<moon-child>
it will do the cas inline for __sync*, but __sync* doesn't give back both the result and the success, which is annoying
X-Scale` is now known as X-Scale
<moon-child>
so I do it with inline asm
<geist>
That’s a feature of gcc that lets you switch to a thing that detects it. It’s kinda a misfeature, so you can turn it off
<moon-child>
geist: you can?
<moon-child>
what's the flag?
<j`ey>
-mno-outline-atomics
<geist>
I dont know off the top of my head, but ,… yeah thats it i think
<moon-child>
'unrecognized command-line option ‘-fno-outline-atomics’; did you mean ‘-fno-inline-atomics’?'
<moon-child>
ditto -mno-...
<geist>
I dunno, but the outline-atomics is the stem
<geist>
May only be on very recent gccs?
<moon-child>
huh there's -moutline-atomics in the manpage, but gcc doesn't like it
<j`ey>
aarch64 gcc?
<geist>
I remember cause we had to set it for the gcc kernel build
<geist>
Maybe only implemented on some arches
<moon-child>
ah yeah 'This option is only applicable when compiling for the base ARMv8.0'
<moon-child>
I'll keep using inline asm for x86 then...
<geist>
Didbn’t know about it for x86 but not equipped to check that out right now
CaCode has quit [Quit: Leaving]
<mrvn>
Does AArch64 have an atomic to replace 2 separate pointers?
<moon-child>
'multiple ll/sc', I think
<moon-child>
but that's basically transactional memory
<mrvn>
I want to set a.next and b.prev atomically.
<moon-child>
oh two contiguous things
<geist>
There’s a double wide load/store with reservation
<moon-child>
yeah
<mrvn>
not contiguous
<geist>
And thus basically a 16byte cas
<moon-child>
oh a.next and b.prev, misread
<mrvn>
The 16byte contiguous we already covered above in the positive.
<moon-child>
anyway, multiple cas is a thing, and I think possibly also multiple ll/sc. As is htm. But none of these are mainstream (yet?)
<geist>
So no you cant atomically fiddle with two non contiguous things
bgs has quit [Read error: Connection reset by peer]
<moon-child>
purportedly, intel is trying to make htm work
<mrvn>
moon-child: multiple cas allows another core to read the wrong data.
bgs has joined #osdev
<moon-child>
mrvn: 'multiple cas' doesn't mean 'cas one thing, then cas another thing'. It means 'cas multiple things at once'
<mrvn>
Now I don't know if I should believe geist or moon-child
<moon-child>
as I said, multiple cas is a thing, but it is not mainstream. So you should not expect to find it on any commodity hardware
mahmutov has quit [Ping timeout: 258 seconds]
<moon-child>
so I agree with geist on 'can't atomically fiddle with two non contiguous things', with the impractical proviso that there are _some_ fringe contexts in which you might be able to
<mrvn>
making a double linkes list thread safe is kind of impossible without a big list-wide lock.
<moon-child>
I wouldn't be surprised if it were possible
<moon-child>
people have come up with some pretty clever lock-free algorithms
heat_ has joined #osdev
<mrvn>
moon-child: all that I've seen fix the forward link and then the backward link and just hope nobody follows the backward link in the mean time.
heat has quit [Read error: Connection reset by peer]
<mrvn>
or they magically wait x ms to make sure no other thread uses a node before freeing it
<moon-child>
hmmm, liblfds seems to only have singly-linked lists
ripmalware_ has joined #osdev
<mrvn>
The requirement for me is to implement: node.remove_from_list() while holding the nodes mutex. No other info, no lock on the list or prev/next nodes.
<mrvn>
problem ist just going to the prev node to lock it risks a deadlock.
ripmalware has quit [Read error: Connection reset by peer]
<moon-child>
what if you set a 'removed' flag on the node before removing it
<moon-child>
then if somebody reads a node, they check the removed flag
<moon-child>
and know to retry if they see it
<moon-child>
downside is you have to keep that flag there forever and can't reuse the node
<moon-child>
(gc periodically, w/e)
<mrvn>
moon-child: that's the "magically waits till nobody reads the node anymore" problem
<moon-child>
so what's wrong with that?
<moon-child>
synchronise periodically
<mrvn>
it leaks memory
<moon-child>
it doesn't
<moon-child>
you can tie the synchronisation period to the number of nodes waiting to be reclaimed
<moon-child>
thereby bounding the latter
<mrvn>
yeah. and that is a stop the world operation.
<moon-child>
it is. But it's amortised
<moon-child>
and you don't have to actually wait until all the nodes are reclaimed before restarting the world. The actual reclamation can be done concurrently
ripmalware_ is now known as ripmalware
<mrvn>
I want to use this for IPC and syscalls so it has to have a really high throughput. And every time it locks a full page.
<heat_>
hey guys
<heat_>
RCU
<heat_>
just saying
heat_ is now known as heat
<mrvn>
I don't want to block all syscalls and IPC 10 times a second.
<moon-child>
stw gc tends to have high throughput
<moon-child>
just sayin
<moon-child>
why are you using doubly-linked lists for ipc anyway?
<heat>
that makes sense
<heat>
list of messages
<heat>
struct list_head style
<moon-child>
yeah. But that can be just singly-linked
<mrvn>
It's all done via message passing
<moon-child>
my queues don't need backlinks
<heat>
but then removing sucks
<heat>
O(n)
<mrvn>
and I want to be able to do cancelations.
<moon-child>
why are you removing from the middle
<moon-child>
oh
<mrvn>
at least it's something I would like to be able to do.
<moon-child>
what about setting a 'cancelled' flag, then, and then knowing to ignore the message once it finally reaches the target?
<mrvn>
My current solution is to use single linked lists and a cancelled flag to drop messages when they reach the front.
<moon-child>
haha
<moon-child>
well, what's wrong with that?
<mrvn>
it locks down memory for a while.
<moon-child>
it is technically less concurrent. But do you expect to be cancelling messages all the time?
<heat>
spinlocks?
<moon-child>
singly-linked list optimises the common case of a message that _does_ reach its destination
<heat>
hm wait this is in userspace isn't it?
<mrvn>
no, kernel.
<heat>
ok, then spinlock
<mrvn>
So I only have to worry about other cores, not sleeping threads.
<heat>
if spinlock becomes a bottleneck, RCU or epoch
<heat>
that's how I usually do queue stuff anyway
<heat>
generally very fast stuff
<heat>
if you indeed profile a bottleneck there, you can move to hardcore things
<mrvn>
My tasks use a doubly linked lists too. But every core has a separate list so there is only ever congestion when moving taks between cores.
<heat>
you don't have a global list of tasks?
<mrvn>
heat: I have that too but that rarely changes. The running/waiting/sleeping/wait_queue list changes all the time.
<mrvn>
If I have a class List { List *next; ...}; class Derived : List { ... }; can I say that the List must ba all Derived objects?
<mrvn>
List::get_next() should return Derived for whatever derived class it is
<mrvn>
In ocaml an object has the classes type and a self type, which is the derived class when you derive.
<moon-child>
mrvn: you have covariance issues there, I think
<moon-child>
suppose I say List x; Derived *y = new Derived; List *z = new List; x.next = y; x.next->next = z; Derived *yn = y->next
<mrvn>
That's ok, then all objects are Lists.
<mrvn>
Derived *y = new Derived; List *z = new List; y.insert(z); should give a type error.
<moon-child>
I don't know the details of C++ oop. But I assume that subclassing is meant to create a subtyping relationship?
<moon-child>
if List::insert can take a List*, then Derived::insert must be able to do so too. (Or, you should be able to convert a Derived* to a List* and call the corresponding insert method)
<moon-child>
otherwise a Derived is not a List
<mrvn>
moon-child: x.insert(std::some_caset<List>(y)); would work.
<mrvn>
-e
<mrvn>
In c++ that happens implicit a lot of the time.
<moon-child>
fine. But if I then say x.next->insert(z), then y->next is now not a Derived*
<mrvn>
In ocaml you can specify it both ways, wether Derviced:foo() should take Lists or Deriveds.
<moon-child>
ocaml has mutation, though, right? So how does it avoid this problem?
<moon-child>
does it punt to runtime like java?
<mrvn>
It has mutation but that has nothing to do with it.
<moon-child>
how do you avoid the situation where you have a Derived *y st y->next is a List* and not a Derived*?
<mrvn>
moon-child: because "List.insert : 'self -> unit" means that y.insert only accepts objects of the same type as y.
<mrvn>
You can't insert a List onto a Derived list.
<moon-child>
can I insert a List into an std::some_cast<List>(Derived*)?
<mrvn>
And you can only insert a Derived into a List if you cast it to List first.
<mrvn>
It kind of looses it's Derived-ness.
<moon-child>
oh--wait--you want something like this? class List { List *next_list; ... }; class Derived: List { Derived *next_derived; }, but without separate names for 'next_list' and 'next_derived'?