tiagosr / Plasm

Playful Assembler: a Racket library/DSL for generating assembly code for 8/16 bit processors and microcontrollers
6 stars 2 forks source link

Labels not working in z80 and avr8 #5

Open Kyuvi opened 4 years ago

Kyuvi commented 4 years ago

The example code in the readme does not work, giving the error

match-lambda*: no matching clause for '(0 'Start 65535)
  location: plasm.rkt:171:2
  context...

I am really not sure about this, but there is no "label?" function in the z80.rkt (or avr8.rkt) files. I am also not sure what the "label-promise" struct is doing as that is what is used in the "between" function where I think this error originates. so unfortunately I have no solutions to this one.

Could you explain how the "label-promise" struct relates to the "label" struct?

tiagosr commented 4 years ago

so, label? is defined in plasm.rkt:387, it's a simple check for whether the value is a symbol at that specific stage - I'm curious how it's actually already done the coercion to a symbol in that location (which is actually supposed to still expect a label-promise%)...

care to share the code that you're using to test? is it the one in the README.md? if so, I'm afraid there might have been some changes in the language or libs that kinda made evident something that was probably half-working (but fundamentally broken) from the start, with promises and such structures

Kyuvi commented 4 years ago

Yes, I am using the code from the README.md when I get this error. labels did not work with avr8.rkt till I added

[rest (%asm-base rest)] 

to the end of the match-lambda in the "make-archtecture" function (PR?), and then it repeats the same error when trying to branch to a label.

When you say changes to the language do you mean Racket iteslf?

also if a file is called from the command line with "racket file-name.rkt" and it has a label before a branch to the label (the README.md has the jp before the label) it gives the error

quote: unbound identifier;
 also, no #%app syntax transformer is bound
  at: quote
  in: (quote Start)

but it ignores this from inside the REPL.

tiagosr commented 4 years ago

I guess the issue with calling a file from "racket file-name.rkt" and getting the #%app syntax transformer notice could be fixed by adding #lang racket to the beginning of the file, I'll update the README.md file to reflect that

Yes, about changes to the language I meant to Racket itself - though I'm getting the impression 5-year-ago me was not particularly well-focused with testing this library thoroughly. I'm getting back at it now, with some newer ideas about how to tackle some of the blockers I found back then

Kyuvi commented 4 years ago

I had used "#lang racket" at the start of the file, so I don't think that is the issue. I am relatively new to racket so I don't fully understand its inner workings

Kyuvi commented 4 years ago

I found out the solution(s) to the "racket file-name.rkt" problem, it is not about the labels but has to do with rackets namespaces and the use of eval in plasm.rkt. There are 3 ways in racket to make it work, I think this

#lang racket
--
 
(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))
 
(define x 1)
(define y 2)
 
(eval '(cons x y) ns) ; produces (1 . 2)

is the most appropriate solution, but it depends on how the program is intended to be used (it is necessary for use in DrRacket as well I think)

The easiest solution is adding this at the beginning of plasm.rkt


#lang racket
(current-namespace (make-base-namespace))

and then there is no need to change the eval line, so it works as a testing tool but I think it only provides racket-base to the namespace. I have not tried current namespace with other arguments though.

Edit: it seems that both can be mixed using

#lang racket
(define-namespace-anchor a)
(current-namespace (namespace-anchor->namespace a))

This works, and there is no need to change the eval line.

Kyuvi commented 4 years ago

I also noticed that if you do not quote the "labels" in the assembly code, they are read (I did not use them in the code) . However using ,en file-name.rkt from inside the repl, the label is only stored in %current-section if it is the first line of code.

Also I got that label on the first line to work by commenting out the (check-consistency) line from the asm function, but trying to use another one gets stuck at (get-label), as that tries to feed the %label-promise function into %label-pos, (in what i suspect is a loop) raising an error. So this (get-label) function,

(define (get-label label)
  (hash-ref (%section-labels %current-section) label
                  (lambda () (%label-promise (list label)
                          (lambda () (%label-pos (get-label label)))))))

is meant to call %label-promise as the "failure result" of hash-ref, is that right?

Isn't this assembler 2-pass? Shouldn't the labels be resolved first? and if they are (correctly) resolved, isn't %label sufficient, negating the need for %label-position?

Kyuvi commented 4 years ago

What I did end up doing was keeping check-consistency commented out of asm, but leaving label-code-inside-list as it was......,

I added a line to label-code


(define (label-code code labels)
  (map (match-lambda
         [(? label? lbl) `(set-label ',(label-uncolon lbl))]
      ;; added line below
         [(? %label-promise? lbl) `(set-label ',(car (label-promise-depends lbl))]
         [rest `,rest]) (label-code-inside-list code labels)))

It seems to work, But it is still a bit of a hack job as I am still not sure of what is really going on. I will test it with larger pieces of code to see if it breaks.

Can I also ask, why in the get-label code, you used (list label) in %label-promise instead of just label ?

tiagosr commented 4 years ago

So, about the number of passes in the assembler, at that time I was experimenting with doing a 1.5-pass assembler - single pass translating, then doing the label dependency graph resolution without need for a full pass. The intention was to do an interactive assembler, in a sort of analytical way.

About the get-label code, a single %label-promise can contain multiple labels for the same specific point in code, and depends accumulates that list. I'll take a look into this whole flow and document it with some more comments, soon.